Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / native_client / src / trusted / service_runtime / sel_ldr.c
1 /*
2  * Copyright (c) 2012 The Native Client Authors. All rights reserved.
3  * Use of this source code is governed by a BSD-style license that can be
4  * found in the LICENSE file.
5  */
6
7 #include <string.h>
8
9 /*
10  * NaCl Simple/secure ELF loader (NaCl SEL).
11  */
12 #include "native_client/src/include/portability.h"
13 #include "native_client/src/include/portability_io.h"
14 #include "native_client/src/include/portability_string.h"
15 #include "native_client/src/include/nacl_macros.h"
16
17 #include "native_client/src/public/desc_metadata_types.h"
18 #include "native_client/src/public/nacl_app.h"
19 #include "native_client/src/public/secure_service.h"
20
21 #include "native_client/src/shared/gio/gio.h"
22 #include "native_client/src/shared/platform/nacl_check.h"
23 #include "native_client/src/shared/platform/nacl_exit.h"
24 #include "native_client/src/shared/platform/nacl_log.h"
25 #include "native_client/src/shared/platform/nacl_sync.h"
26 #include "native_client/src/shared/platform/nacl_sync_checked.h"
27 #include "native_client/src/shared/platform/nacl_time.h"
28 #include "native_client/src/shared/srpc/nacl_srpc.h"
29
30 #include "native_client/src/trusted/desc/nacl_desc_base.h"
31 #include "native_client/src/trusted/desc/nacl_desc_conn_cap.h"
32 #include "native_client/src/trusted/desc/nacl_desc_imc.h"
33 #include "native_client/src/trusted/desc/nacl_desc_io.h"
34 #include "native_client/src/trusted/desc/nrd_xfer.h"
35 #include "native_client/src/trusted/desc_cacheability/desc_cacheability.h"
36 #include "native_client/src/trusted/fault_injection/fault_injection.h"
37 #include "native_client/src/trusted/fault_injection/test_injection.h"
38 #include "native_client/src/trusted/gio/gio_nacl_desc.h"
39 #include "native_client/src/trusted/gio/gio_shm.h"
40 #include "native_client/src/trusted/interval_multiset/nacl_interval_range_tree_intern.h"
41 #include "native_client/src/trusted/service_runtime/arch/sel_ldr_arch.h"
42 #include "native_client/src/trusted/service_runtime/include/bits/nacl_syscalls.h"
43 #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
44 #include "native_client/src/trusted/service_runtime/include/sys/stat.h"
45 #include "native_client/src/trusted/service_runtime/include/sys/time.h"
46 #include "native_client/src/trusted/service_runtime/nacl_app.h"
47 #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
48 #include "native_client/src/trusted/service_runtime/nacl_desc_effector_ldr.h"
49 #include "native_client/src/trusted/service_runtime/nacl_globals.h"
50 #include "native_client/src/trusted/service_runtime/nacl_resource.h"
51 #include "native_client/src/trusted/service_runtime/nacl_reverse_quota_interface.h"
52 #include "native_client/src/trusted/service_runtime/nacl_syscall_common.h"
53 #include "native_client/src/trusted/service_runtime/nacl_syscall_handlers.h"
54 #include "native_client/src/trusted/service_runtime/nacl_valgrind_hooks.h"
55 #include "native_client/src/trusted/service_runtime/name_service/default_name_service.h"
56 #include "native_client/src/trusted/service_runtime/name_service/name_service.h"
57 #include "native_client/src/trusted/service_runtime/sel_addrspace.h"
58 #include "native_client/src/trusted/service_runtime/sel_ldr.h"
59 #include "native_client/src/trusted/service_runtime/sel_memory.h"
60 #include "native_client/src/trusted/service_runtime/sel_ldr_thread_interface.h"
61 #include "native_client/src/trusted/simple_service/nacl_simple_rservice.h"
62 #include "native_client/src/trusted/simple_service/nacl_simple_service.h"
63 #include "native_client/src/trusted/threading/nacl_thread_interface.h"
64 #include "native_client/src/trusted/validator/validation_cache.h"
65
66 static int IsEnvironmentVariableSet(char const *env_name) {
67   return NULL != getenv(env_name);
68 }
69
70 static int ShouldEnableDyncodeSyscalls(void) {
71   return !IsEnvironmentVariableSet("NACL_DISABLE_DYNCODE_SYSCALLS");
72 }
73
74 static int ShouldEnableDynamicLoading(void) {
75   return !IsEnvironmentVariableSet("NACL_DISABLE_DYNAMIC_LOADING");
76 }
77
78 int NaClAppWithSyscallTableCtor(struct NaClApp               *nap,
79                                 struct NaClSyscallTableEntry *table) {
80   struct NaClDescEffectorLdr  *effp;
81
82   /* Zero-initialize in case we miss any fields below. */
83   memset(nap, 0, sizeof(*nap));
84
85   /* The validation cache will be injected later, if it exists. */
86   nap->validation_cache = NULL;
87
88   nap->validator = NaClCreateValidator();
89
90   /* Get the set of features that the CPU we're running on supports. */
91   /* These may be adjusted later in sel_main.c for fixed-feature CPU mode. */
92   nap->cpu_features = (NaClCPUFeatures *) malloc(
93       nap->validator->CPUFeatureSize);
94   if (NULL == nap->cpu_features) {
95     goto cleanup_none;
96   }
97   nap->validator->GetCurrentCPUFeatures(nap->cpu_features);
98   nap->fixed_feature_cpu_mode = 0;
99
100   nap->addr_bits = NACL_MAX_ADDR_BITS;
101
102   nap->stack_size = NACL_DEFAULT_STACK_MAX;
103   nap->initial_nexe_max_code_bytes = 0;
104
105   nap->mem_start = 0;
106
107 #if (NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 \
108      && NACL_BUILD_SUBARCH == 32)
109   nap->pcrel_thunk = 0;
110   nap->pcrel_thunk_end = 0;
111 #endif
112 #if (NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 \
113      && NACL_BUILD_SUBARCH == 64)
114   nap->nacl_syscall_addr = 0;
115   nap->get_tls_fast_path1_addr = 0;
116   nap->get_tls_fast_path2_addr = 0;
117 #endif
118
119   nap->static_text_end = 0;
120   nap->dynamic_text_start = 0;
121   nap->dynamic_text_end = 0;
122   nap->rodata_start = 0;
123   nap->data_start = 0;
124   nap->data_end = 0;
125
126   nap->initial_entry_pt = 0;
127   nap->user_entry_pt = 0;
128
129   if (!DynArrayCtor(&nap->threads, 2)) {
130     goto cleanup_cpu_features;
131   }
132   if (!DynArrayCtor(&nap->desc_tbl, 2)) {
133     goto cleanup_threads;
134   }
135   if (!NaClVmmapCtor(&nap->mem_map)) {
136     goto cleanup_desc_tbl;
137   }
138
139   nap->mem_io_regions = (struct NaClIntervalMultiset *) malloc(
140       sizeof(struct NaClIntervalRangeTree));
141   if (NULL == nap->mem_io_regions) {
142     goto cleanup_mem_map;
143   }
144
145   if (!NaClIntervalRangeTreeCtor((struct NaClIntervalRangeTree *)
146                                  nap->mem_io_regions)) {
147     free(nap->mem_io_regions);
148     nap->mem_io_regions = NULL;
149     goto cleanup_mem_map;
150   }
151
152   effp = (struct NaClDescEffectorLdr *) malloc(sizeof *effp);
153   if (NULL == effp) {
154     goto cleanup_mem_io_regions;
155   }
156   if (!NaClDescEffectorLdrCtor(effp, nap)) {
157     goto cleanup_effp_free;
158   }
159   nap->effp = (struct NaClDescEffector *) effp;
160
161   nap->enable_dyncode_syscalls = ShouldEnableDyncodeSyscalls();
162   nap->use_shm_for_dynamic_text = ShouldEnableDynamicLoading();
163   nap->text_shm = NULL;
164   if (!NaClMutexCtor(&nap->dynamic_load_mutex)) {
165     goto cleanup_effp_free;
166   }
167   nap->dynamic_page_bitmap = NULL;
168
169   nap->dynamic_regions = NULL;
170   nap->num_dynamic_regions = 0;
171   nap->dynamic_regions_allocated = 0;
172   nap->dynamic_delete_generation = 0;
173
174   nap->dynamic_mapcache_offset = 0;
175   nap->dynamic_mapcache_size = 0;
176   nap->dynamic_mapcache_ret = 0;
177
178   nap->service_port = NULL;
179   nap->service_address = NULL;
180   nap->secure_service_port = NULL;
181   nap->secure_service_address = NULL;
182   nap->bootstrap_channel = NULL;
183   nap->secure_service = NULL;
184   nap->irt_loaded = 0;
185   nap->main_exe_prevalidated = 0;
186
187   nap->kernel_service = NULL;
188   nap->resource_phase = NACL_RESOURCE_PHASE_START;
189   if (!NaClResourceNaClAppInit(&nap->resources, nap)) {
190     goto cleanup_dynamic_load_mutex;
191   }
192
193   if (!NaClMutexCtor(&nap->mu)) {
194     goto cleanup_dynamic_load_mutex;
195   }
196   if (!NaClCondVarCtor(&nap->cv)) {
197     goto cleanup_mu;
198   }
199
200 #if NACL_WINDOWS
201   nap->vm_hole_may_exist = 0;
202   nap->threads_launching = 0;
203 #endif
204
205   nap->syscall_table = table;
206
207   nap->runtime_host_interface = NULL;
208   nap->desc_quota_interface = NULL;
209
210   nap->module_initialization_state = NACL_MODULE_UNINITIALIZED;
211   nap->module_load_status = LOAD_STATUS_UNKNOWN;
212
213   nap->name_service = (struct NaClNameService *) malloc(
214       sizeof *nap->name_service);
215   if (NULL == nap->name_service) {
216     goto cleanup_cv;
217   }
218   if (!NaClNameServiceCtor(nap->name_service,
219                            NaClAddrSpSquattingThreadIfFactoryFunction,
220                            (void *) nap)) {
221     free(nap->name_service);
222     goto cleanup_cv;
223   }
224   nap->name_service_conn_cap = NaClDescRef(nap->name_service->
225                                            base.base.bound_and_cap[1]);
226   if (!NaClDefaultNameServiceInit(nap->name_service)) {
227     goto cleanup_name_service;
228   }
229
230   nap->ignore_validator_result = 0;
231   nap->skip_validator = 0;
232   nap->validator_stub_out_mode = 0;
233
234   if (IsEnvironmentVariableSet("NACL_DANGEROUS_ENABLE_FILE_ACCESS")) {
235     NaClInsecurelyBypassAllAclChecks();
236     NaClLog(LOG_INFO, "DANGER: ENABLED FILE ACCESS\n");
237   }
238
239   nap->enable_list_mappings = 0;
240   if (IsEnvironmentVariableSet("NACL_DANGEROUS_ENABLE_LIST_MAPPINGS")) {
241     /*
242      * This syscall is not actually know to be dangerous, but is not yet
243      * exposed by our public API.
244      */
245     NaClLog(LOG_INFO, "DANGER: ENABLED LIST_MAPPINGS\n");
246     nap->enable_list_mappings = 1;
247   }
248
249   if (!NaClMutexCtor(&nap->threads_mu)) {
250     goto cleanup_name_service;
251   }
252   nap->num_threads = 0;
253   if (!NaClFastMutexCtor(&nap->desc_mu)) {
254     goto cleanup_threads_mu;
255   }
256
257   nap->running = 0;
258   nap->exit_status = -1;
259
260 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
261   nap->code_seg_sel = 0;
262   nap->data_seg_sel = 0;
263 #endif
264
265   nap->debug_stub_callbacks = NULL;
266   nap->exception_handler = 0;
267   if (!NaClMutexCtor(&nap->exception_mu)) {
268     goto cleanup_desc_mu;
269   }
270   nap->enable_exception_handling = 0;
271 #if NACL_WINDOWS
272   nap->debug_exception_handler_state = NACL_DEBUG_EXCEPTION_HANDLER_NOT_STARTED;
273   nap->attach_debug_exception_handler_func = NULL;
274 #endif
275   nap->enable_faulted_thread_queue = 0;
276   nap->faulted_thread_count = 0;
277 #if NACL_WINDOWS
278   nap->faulted_thread_event = INVALID_HANDLE_VALUE;
279 #else
280   nap->faulted_thread_fd_read = -1;
281   nap->faulted_thread_fd_write = -1;
282 #endif
283
284
285 #if NACL_LINUX || NACL_OSX
286   /*
287    * Try to pre-cache information that we can't obtain with the outer
288    * sandbox on.  If the outer sandbox has already been enabled, this
289    * will just set sc_nprocessors_onln to -1, and it is the
290    * responsibility of the caller to replace this with a sane value
291    * after the Ctor returns.
292    */
293   nap->sc_nprocessors_onln = sysconf(_SC_NPROCESSORS_ONLN);
294 #endif
295
296   if (!NaClMutexCtor(&nap->futex_wait_list_mu)) {
297     goto cleanup_exception_mu;
298   }
299   nap->futex_wait_list_head.next = &nap->futex_wait_list_head;
300   nap->futex_wait_list_head.prev = &nap->futex_wait_list_head;
301
302   return 1;
303
304  cleanup_exception_mu:
305   NaClMutexDtor(&nap->exception_mu);
306  cleanup_desc_mu:
307   NaClFastMutexDtor(&nap->desc_mu);
308  cleanup_threads_mu:
309   NaClMutexDtor(&nap->threads_mu);
310  cleanup_name_service:
311   NaClDescUnref(nap->name_service_conn_cap);
312   NaClRefCountUnref((struct NaClRefCount *) nap->name_service);
313  cleanup_cv:
314   NaClCondVarDtor(&nap->cv);
315  cleanup_mu:
316   NaClMutexDtor(&nap->mu);
317  cleanup_dynamic_load_mutex:
318   NaClMutexDtor(&nap->dynamic_load_mutex);
319  cleanup_effp_free:
320   free(nap->effp);
321  cleanup_mem_io_regions:
322   NaClIntervalMultisetDelete(nap->mem_io_regions);
323   nap->mem_io_regions = NULL;
324  cleanup_mem_map:
325   NaClVmmapDtor(&nap->mem_map);
326  cleanup_desc_tbl:
327   DynArrayDtor(&nap->desc_tbl);
328  cleanup_threads:
329   DynArrayDtor(&nap->threads);
330  cleanup_cpu_features:
331   free(nap->cpu_features);
332  cleanup_none:
333   return 0;
334 }
335
336 int NaClAppCtor(struct NaClApp *nap) {
337   return NaClAppWithSyscallTableCtor(nap, nacl_syscall);
338 }
339
340 struct NaClApp *NaClAppCreate(void) {
341   struct NaClApp *nap = malloc(sizeof(struct NaClApp));
342   if (nap == NULL)
343     NaClLog(LOG_FATAL, "Failed to allocate NaClApp\n");
344   if (!NaClAppCtor(nap))
345     NaClLog(LOG_FATAL, "NaClAppCtor() failed\n");
346   return nap;
347 }
348
349 /*
350  * unaligned little-endian load.  precondition: nbytes should never be
351  * more than 8.
352  */
353 static uint64_t NaClLoadMem(uintptr_t addr,
354                             size_t    user_nbytes) {
355   uint64_t      value = 0;
356
357   CHECK(0 != user_nbytes && user_nbytes <= 8);
358
359   do {
360     value = value << 8;
361     value |= ((uint8_t *) addr)[--user_nbytes];
362   } while (user_nbytes > 0);
363   return value;
364 }
365
366 #define GENERIC_LOAD(bits) \
367   static uint ## bits ## _t NaClLoad ## bits(uintptr_t addr) { \
368     return (uint ## bits ## _t) NaClLoadMem(addr, sizeof(uint ## bits ## _t)); \
369   }
370
371 #if NACL_TARGET_SUBARCH == 32
372 GENERIC_LOAD(32)
373 #endif
374 GENERIC_LOAD(64)
375
376 #undef GENERIC_LOAD
377
378 /*
379  * unaligned little-endian store
380  */
381 static void NaClStoreMem(uintptr_t  addr,
382                          size_t     nbytes,
383                          uint64_t   value) {
384   size_t i;
385
386   CHECK(nbytes <= 8);
387
388   for (i = 0; i < nbytes; ++i) {
389     ((uint8_t *) addr)[i] = (uint8_t) value;
390     value = value >> 8;
391   }
392 }
393
394 #define GENERIC_STORE(bits) \
395   static void NaClStore ## bits(uintptr_t addr, \
396                                 uint ## bits ## _t v) { \
397     NaClStoreMem(addr, sizeof(uint ## bits ## _t), v); \
398   }
399
400 GENERIC_STORE(16)
401 GENERIC_STORE(32)
402 GENERIC_STORE(64)
403
404 #undef GENERIC_STORE
405
406 struct NaClPatchInfo *NaClPatchInfoCtor(struct NaClPatchInfo *self) {
407   if (NULL != self) {
408     memset(self, 0, sizeof *self);
409   }
410   return self;
411 }
412
413 /*
414  * This function is called by NaClLoadTrampoline and NaClLoadSpringboard to
415  * patch a single memory location specified in NaClPatchInfo structure.
416  */
417 void  NaClApplyPatchToMemory(struct NaClPatchInfo  *patch) {
418   size_t    i;
419   size_t    offset;
420   int64_t   reloc;
421   uintptr_t target_addr;
422
423   memcpy((void *) patch->dst, (void *) patch->src, patch->nbytes);
424
425   reloc = patch->dst - patch->src;
426
427
428   for (i = 0; i < patch->num_abs64; ++i) {
429     offset = patch->abs64[i].target - patch->src;
430     target_addr = patch->dst + offset;
431     NaClStore64(target_addr, patch->abs64[i].value);
432   }
433
434   for (i = 0; i < patch->num_abs32; ++i) {
435     offset = patch->abs32[i].target - patch->src;
436     target_addr = patch->dst + offset;
437     NaClStore32(target_addr, (uint32_t) patch->abs32[i].value);
438   }
439
440   for (i = 0; i < patch->num_abs16; ++i) {
441     offset = patch->abs16[i].target - patch->src;
442     target_addr = patch->dst + offset;
443     NaClStore16(target_addr, (uint16_t) patch->abs16[i].value);
444   }
445
446   for (i = 0; i < patch->num_rel64; ++i) {
447     offset = patch->rel64[i] - patch->src;
448     target_addr = patch->dst + offset;
449     NaClStore64(target_addr, NaClLoad64(target_addr) - reloc);
450   }
451
452   /*
453    * rel32 is only supported on 32-bit architectures. The range of a relative
454    * relocation in untrusted space is +/- 4GB. This can be represented as
455    * an unsigned 32-bit value mod 2^32, which is handy on a 32 bit system since
456    * all 32-bit pointer arithmetic is implicitly mod 2^32. On a 64 bit system,
457    * however, pointer arithmetic is implicitly modulo 2^64, which isn't as
458    * helpful for our purposes. We could simulate the 32-bit behavior by
459    * explicitly modding all relative addresses by 2^32, but that seems like an
460    * expensive way to save a few bytes per reloc.
461    */
462 #if NACL_TARGET_SUBARCH == 32
463   for (i = 0; i < patch->num_rel32; ++i) {
464     offset = patch->rel32[i] - patch->src;
465     target_addr = patch->dst + offset;
466     NaClStore32(target_addr,
467       (uint32_t) NaClLoad32(target_addr) - (int32_t) reloc);
468   }
469 #endif
470 }
471
472
473 /*
474  * Install syscall trampolines at all possible well-formed entry
475  * points within the trampoline pages.  Many of these syscalls will
476  * correspond to unimplemented system calls and will just abort the
477  * program.
478  */
479 void  NaClLoadTrampoline(struct NaClApp *nap) {
480   int         num_syscalls;
481   int         i;
482   uintptr_t   addr;
483
484 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
485   if (!NaClMakePcrelThunk(nap)) {
486     NaClLog(LOG_FATAL, "NaClMakePcrelThunk failed!\n");
487   }
488 #endif
489 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64
490   if (!NaClMakeDispatchAddrs(nap)) {
491     NaClLog(LOG_FATAL, "NaClMakeDispatchAddrs failed!\n");
492   }
493 #endif
494   NaClFillTrampolineRegion(nap);
495
496   /*
497    * Do not bother to fill in the contents of page 0, since we make it
498    * inaccessible later (see sel_addrspace.c, NaClMemoryProtection)
499    * anyway to help detect NULL pointer errors, and we might as well
500    * not dirty the page.
501    *
502    * The last syscall entry point is used for springboard code.
503    */
504   num_syscalls = ((NACL_TRAMPOLINE_END - NACL_SYSCALL_START_ADDR)
505                   / NACL_SYSCALL_BLOCK_SIZE) - 1;
506
507   NaClLog(2, "num_syscalls = %d (0x%x)\n", num_syscalls, num_syscalls);
508
509   for (i = 0, addr = nap->mem_start + NACL_SYSCALL_START_ADDR;
510        i < num_syscalls;
511        ++i, addr += NACL_SYSCALL_BLOCK_SIZE) {
512     NaClPatchOneTrampoline(nap, addr);
513   }
514 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64
515   NaClPatchOneTrampolineCall(nap->get_tls_fast_path1_addr,
516                              nap->mem_start + NACL_SYSCALL_START_ADDR
517                              + NACL_SYSCALL_BLOCK_SIZE * NACL_sys_tls_get);
518   NaClPatchOneTrampolineCall(nap->get_tls_fast_path2_addr,
519                              nap->mem_start + NACL_SYSCALL_START_ADDR
520                              + (NACL_SYSCALL_BLOCK_SIZE *
521                                 NACL_sys_second_tls_get));
522 #endif
523
524   NACL_TEST_INJECTION(ChangeTrampolines, (nap));
525 }
526
527 void  NaClMemRegionPrinter(void                   *state,
528                            struct NaClVmmapEntry  *entry) {
529   struct Gio *gp = (struct Gio *) state;
530
531   gprintf(gp, "\nPage   %"NACL_PRIdPTR" (0x%"NACL_PRIxPTR")\n",
532           entry->page_num, entry->page_num);
533   gprintf(gp,   "npages %"NACL_PRIdS" (0x%"NACL_PRIxS")\n", entry->npages,
534           entry->npages);
535   gprintf(gp,   "start vaddr 0x%"NACL_PRIxPTR"\n",
536           entry->page_num << NACL_PAGESHIFT);
537   gprintf(gp,   "end vaddr   0x%"NACL_PRIxPTR"\n",
538           (entry->page_num + entry->npages) << NACL_PAGESHIFT);
539   gprintf(gp,   "prot   0x%08x\n", entry->prot);
540   gprintf(gp,   "%sshared/backed by a file\n",
541           (NULL == entry->desc) ? "not " : "");
542 }
543
544 void  NaClAppPrintDetails(struct NaClApp  *nap,
545                           struct Gio      *gp) {
546   NaClXMutexLock(&nap->mu);
547   gprintf(gp,
548           "NaClAppPrintDetails((struct NaClApp *) 0x%08"NACL_PRIxPTR","
549           "(struct Gio *) 0x%08"NACL_PRIxPTR")\n", (uintptr_t) nap,
550           (uintptr_t) gp);
551   gprintf(gp, "addr space size:  2**%"NACL_PRId32"\n", nap->addr_bits);
552   gprintf(gp, "stack size:       0x%08"NACL_PRIx32"\n", nap->stack_size);
553
554   gprintf(gp, "mem start addr:   0x%08"NACL_PRIxPTR"\n", nap->mem_start);
555   /*           123456789012345678901234567890 */
556
557   gprintf(gp, "static_text_end:   0x%08"NACL_PRIxPTR"\n", nap->static_text_end);
558   gprintf(gp, "end-of-text:       0x%08"NACL_PRIxPTR"\n",
559           NaClEndOfStaticText(nap));
560   gprintf(gp, "rodata:            0x%08"NACL_PRIxPTR"\n", nap->rodata_start);
561   gprintf(gp, "data:              0x%08"NACL_PRIxPTR"\n", nap->data_start);
562   gprintf(gp, "data_end:          0x%08"NACL_PRIxPTR"\n", nap->data_end);
563   gprintf(gp, "break_addr:        0x%08"NACL_PRIxPTR"\n", nap->break_addr);
564
565   gprintf(gp, "ELF initial entry point:  0x%08x\n", nap->initial_entry_pt);
566   gprintf(gp, "ELF user entry point:  0x%08x\n", nap->user_entry_pt);
567   gprintf(gp, "memory map:\n");
568   NaClVmmapVisit(&nap->mem_map,
569                  NaClMemRegionPrinter,
570                  gp);
571   NaClXMutexUnlock(&nap->mu);
572 }
573
574 struct NaClDesc *NaClAppGetDescMu(struct NaClApp *nap,
575                                   int            d) {
576   struct NaClDesc *result;
577
578   result = (struct NaClDesc *) DynArrayGet(&nap->desc_tbl, d);
579   if (NULL != result) {
580     NaClDescRef(result);
581   }
582
583   return result;
584 }
585
586 void NaClAppSetDescMu(struct NaClApp   *nap,
587                       int              d,
588                       struct NaClDesc  *ndp) {
589   struct NaClDesc *result;
590
591   result = (struct NaClDesc *) DynArrayGet(&nap->desc_tbl, d);
592   NaClDescSafeUnref(result);
593
594   if (!DynArraySet(&nap->desc_tbl, d, ndp)) {
595     NaClLog(LOG_FATAL,
596             "NaClAppSetDesc: could not set descriptor %d to 0x%08"
597             NACL_PRIxPTR"\n",
598             d,
599             (uintptr_t) ndp);
600   }
601 }
602
603 int32_t NaClAppSetDescAvailMu(struct NaClApp  *nap,
604                               struct NaClDesc *ndp) {
605   size_t pos;
606
607   pos = DynArrayFirstAvail(&nap->desc_tbl);
608
609   if (pos > INT32_MAX) {
610     NaClLog(LOG_FATAL,
611             ("NaClAppSetDescAvailMu: DynArrayFirstAvail returned a value"
612              " that is greather than 2**31-1.\n"));
613   }
614
615   NaClAppSetDescMu(nap, (int) pos, ndp);
616
617   return (int32_t) pos;
618 }
619
620 struct NaClDesc *NaClAppGetDesc(struct NaClApp *nap,
621                                 int            d) {
622   struct NaClDesc *res;
623
624   NaClFastMutexLock(&nap->desc_mu);
625   res = NaClAppGetDescMu(nap, d);
626   NaClFastMutexUnlock(&nap->desc_mu);
627   return res;
628 }
629
630 void NaClAppSetDesc(struct NaClApp   *nap,
631                     int              d,
632                     struct NaClDesc  *ndp) {
633   NaClFastMutexLock(&nap->desc_mu);
634   NaClAppSetDescMu(nap, d, ndp);
635   NaClFastMutexUnlock(&nap->desc_mu);
636 }
637
638 int32_t NaClAppSetDescAvail(struct NaClApp  *nap,
639                             struct NaClDesc *ndp) {
640   int32_t pos;
641
642   NaClFastMutexLock(&nap->desc_mu);
643   pos = NaClAppSetDescAvailMu(nap, ndp);
644   NaClFastMutexUnlock(&nap->desc_mu);
645
646   return pos;
647 }
648
649 int NaClAddThreadMu(struct NaClApp        *nap,
650                     struct NaClAppThread  *natp) {
651   size_t pos;
652
653   pos = DynArrayFirstAvail(&nap->threads);
654
655   if (!DynArraySet(&nap->threads, pos, natp)) {
656     NaClLog(LOG_FATAL,
657             "NaClAddThreadMu: DynArraySet at position %"NACL_PRIuS" failed\n",
658             pos);
659   }
660   ++nap->num_threads;
661   return (int) pos;
662 }
663
664 int NaClAddThread(struct NaClApp        *nap,
665                   struct NaClAppThread  *natp) {
666   int pos;
667
668   NaClXMutexLock(&nap->threads_mu);
669   pos = NaClAddThreadMu(nap, natp);
670   NaClXMutexUnlock(&nap->threads_mu);
671
672   return pos;
673 }
674
675 void NaClRemoveThreadMu(struct NaClApp  *nap,
676                         int             thread_num) {
677   if (NULL == DynArrayGet(&nap->threads, thread_num)) {
678     NaClLog(LOG_FATAL,
679             "NaClRemoveThreadMu:: thread to be removed is not in the table\n");
680   }
681   if (nap->num_threads == 0) {
682     NaClLog(LOG_FATAL,
683             "NaClRemoveThreadMu:: num_threads cannot be 0!!!\n");
684   }
685   --nap->num_threads;
686   if (!DynArraySet(&nap->threads, thread_num, (struct NaClAppThread *) NULL)) {
687     NaClLog(LOG_FATAL,
688             "NaClRemoveThreadMu:: DynArraySet at position %d failed\n",
689             thread_num);
690   }
691 }
692
693 void NaClRemoveThread(struct NaClApp  *nap,
694                       int             thread_num) {
695   NaClXMutexLock(&nap->threads_mu);
696   NaClRemoveThreadMu(nap, thread_num);
697   NaClXMutexUnlock(&nap->threads_mu);
698 }
699
700 struct NaClAppThread *NaClGetThreadMu(struct NaClApp  *nap,
701                                       int             thread_num) {
702   return (struct NaClAppThread *) DynArrayGet(&nap->threads, thread_num);
703 }
704
705 void NaClAddHostDescriptor(struct NaClApp *nap,
706                            int            host_os_desc,
707                            int            flag,
708                            int            nacl_desc) {
709   struct NaClDescIoDesc *dp;
710
711   NaClLog(4,
712           "NaClAddHostDescriptor: host %d as nacl desc %d, flag 0x%x\n",
713           host_os_desc,
714           nacl_desc,
715           flag);
716   dp = NaClDescIoDescMake(NaClHostDescPosixMake(host_os_desc, flag));
717   if (NULL == dp) {
718     NaClLog(LOG_FATAL, "NaClAddHostDescriptor: NaClDescIoDescMake failed\n");
719   }
720   NaClAppSetDesc(nap, nacl_desc, (struct NaClDesc *) dp);
721 }
722
723 void NaClAddImcHandle(struct NaClApp  *nap,
724                       NaClHandle      h,
725                       int             nacl_desc) {
726   struct NaClDescImcDesc  *dp;
727
728   NaClLog(4,
729           ("NaClAddImcHandle: importing NaClHandle %"NACL_PRIxPTR
730            " as nacl desc %d\n"),
731           (uintptr_t) h,
732           nacl_desc);
733   dp = (struct NaClDescImcDesc *) malloc(sizeof *dp);
734   if (NACL_FI_ERROR_COND("NaClAddImcHandle__malloc", NULL == dp)) {
735     NaClLog(LOG_FATAL, "NaClAddImcHandle: no memory\n");
736   }
737   if (NACL_FI_ERROR_COND("NaClAddImcHandle__ctor",
738                          !NaClDescImcDescCtor(dp, h))) {
739     NaClLog(LOG_FATAL, ("NaClAddImcHandle: cannot construct"
740                         " IMC descriptor object\n"));
741   }
742   NaClAppSetDesc(nap, nacl_desc, (struct NaClDesc *) dp);
743 }
744
745
746 static struct {
747   int         d;
748   char const  *env_name;
749   int         nacl_flags;
750   int         mode;
751 } const g_nacl_redir_control[] = {
752   { 0, "NACL_EXE_STDIN",
753     NACL_ABI_O_RDONLY, 0, },
754   { 1, "NACL_EXE_STDOUT",
755     NACL_ABI_O_WRONLY | NACL_ABI_O_APPEND | NACL_ABI_O_CREAT, 0777, },
756   { 2, "NACL_EXE_STDERR",
757     NACL_ABI_O_WRONLY | NACL_ABI_O_APPEND | NACL_ABI_O_CREAT, 0777, },
758 };
759
760 /*
761  * File redirection is impossible if an outer sandbox is in place.
762  * For the command-line embedding, we sometimes have an outer sandbox:
763  * on OSX, it is enabled after loading the file is loaded.  On the
764  * other hand, device redirection (DEBUG_ONLY:dev://postmessage) is
765  * impossible until the reverse channel setup has occurred.
766  *
767  * Because of this, we run NaClProcessRedirControl twice: once to
768  * process default inheritance, file redirection early on, and once
769  * after the reverse channel is in place to handle the device
770  * redirection.  We try to hide knowledge about which redirection
771  * control values can be handled in which phases by allowing the
772  * NaClResourceOpen to fail, and only in the last phase do we check
773  * that the redirection succeeded in *some* phase.
774  */
775 static void NaClProcessRedirControl(struct NaClApp *nap) {
776
777   size_t          ix;
778   char const      *env;
779   struct NaClDesc *ndp;
780
781   for (ix = 0; ix < NACL_ARRAY_SIZE(g_nacl_redir_control); ++ix) {
782     ndp = NULL;
783     if (NULL != (env = getenv(g_nacl_redir_control[ix].env_name))) {
784       NaClLog(4, "getenv(%s) -> %s\n", g_nacl_redir_control[ix].env_name, env);
785       ndp = NaClResourceOpen((struct NaClResource *) &nap->resources,
786                              env,
787                              g_nacl_redir_control[ix].nacl_flags,
788                              g_nacl_redir_control[ix].mode);
789       NaClLog(4, " NaClResourceOpen returned %"NACL_PRIxPTR"\n",
790               (uintptr_t) ndp);
791     }
792
793     if (NULL != ndp) {
794       NaClLog(4, "Setting descriptor %d\n", (int) ix);
795       NaClAppSetDesc(nap, (int) ix, ndp);
796     } else if (NACL_RESOURCE_PHASE_START == nap->resource_phase) {
797       /*
798        * Environment not set or redirect failed -- handle default inheritance.
799        */
800       NaClAddHostDescriptor(nap, DUP(g_nacl_redir_control[ix].d),
801                             g_nacl_redir_control[ix].nacl_flags, (int) ix);
802     }
803   }
804 }
805
806 /*
807  * Process default descriptor inheritance.  This means dup'ing
808  * descriptors 0-2 and making them available to the NaCl App.
809  *
810  * When standard input is inherited, this could result in a NaCl
811  * module competing for input from the terminal; for graphical /
812  * browser plugin environments, this never is allowed to happen, and
813  * having this is useful for debugging, and for potential standalone
814  * text-mode applications of NaCl.
815  *
816  * TODO(bsy): consider whether default inheritance should occur only
817  * in debug mode.
818  */
819 void NaClAppInitialDescriptorHookup(struct NaClApp  *nap) {
820
821   NaClLog(4, "Processing I/O redirection/inheritance from environment\n");
822   nap->resource_phase = NACL_RESOURCE_PHASE_START;
823   NaClProcessRedirControl(nap);
824   NaClLog(4, "... done.\n");
825 }
826
827 void NaClCreateServiceSocket(struct NaClApp *nap) {
828   struct NaClDesc *secure_pair[2];
829   struct NaClDesc *pair[2];
830
831   NaClLog(3, "Entered NaClCreateServiceSocket\n");
832
833   if (NACL_FI_ERROR_COND("NaClCreateServiceSocket__secure_boundsock",
834                          0 != NaClCommonDescMakeBoundSock(secure_pair))) {
835     NaClLog(LOG_FATAL, "Cound not create secure service socket\n");
836   }
837   NaClLog(4,
838           "got bound socket at 0x%08"NACL_PRIxPTR", "
839           "addr at 0x%08"NACL_PRIxPTR"\n",
840           (uintptr_t) secure_pair[0],
841           (uintptr_t) secure_pair[1]);
842
843   NaClDescSafeUnref(nap->secure_service_port);
844   nap->secure_service_port = secure_pair[0];
845
846   NaClDescSafeUnref(nap->secure_service_address);
847   nap->secure_service_address = secure_pair[1];
848
849   if (NACL_FI_ERROR_COND("NaClCreateServiceSocket__boundsock",
850                          0 != NaClCommonDescMakeBoundSock(pair))) {
851     NaClLog(LOG_FATAL, "Cound not create service socket\n");
852   }
853   NaClLog(4,
854           "got bound socket at 0x%08"NACL_PRIxPTR", "
855           "addr at 0x%08"NACL_PRIxPTR"\n",
856           (uintptr_t) pair[0],
857           (uintptr_t) pair[1]);
858   NaClAppSetDesc(nap, NACL_SERVICE_PORT_DESCRIPTOR, pair[0]);
859   NaClAppSetDesc(nap, NACL_SERVICE_ADDRESS_DESCRIPTOR, pair[1]);
860
861   NaClDescSafeUnref(nap->service_port);
862
863   nap->service_port = pair[0];
864   NaClDescRef(nap->service_port);
865
866   NaClDescSafeUnref(nap->service_address);
867
868   nap->service_address = pair[1];
869   NaClDescRef(nap->service_address);
870
871   NaClLog(4, "Leaving NaClCreateServiceSocket\n");
872 }
873
874 /*
875  * Import the |inherited_desc| descriptor as an IMC handle, save a
876  * reference to it at nap->bootstrap_channel, then send the
877  * service_address over that channel.
878  */
879 void NaClSetUpBootstrapChannel(struct NaClApp  *nap,
880                                NaClHandle      inherited_desc) {
881   struct NaClDescImcDesc      *channel;
882   struct NaClImcTypedMsgHdr   hdr;
883   struct NaClDesc             *descs[2];
884   ssize_t                     rv;
885
886   NaClLog(4,
887           "NaClSetUpBootstrapChannel(0x%08"NACL_PRIxPTR", %"NACL_PRIdPTR")\n",
888           (uintptr_t) nap,
889           (uintptr_t) inherited_desc);
890
891   channel = (struct NaClDescImcDesc *) malloc(sizeof *channel);
892   if (NULL == channel) {
893     NaClLog(LOG_FATAL, "NaClSetUpBootstrapChannel: no memory\n");
894   }
895   if (!NaClDescImcDescCtor(channel, inherited_desc)) {
896     NaClLog(LOG_FATAL,
897             ("NaClSetUpBootstrapChannel: cannot construct IMC descriptor"
898              " object for inherited descriptor %"NACL_PRIdPTR"\n"),
899             (uintptr_t) inherited_desc);
900     return;
901   }
902   if (NULL == nap->secure_service_address) {
903     NaClLog(LOG_FATAL,
904             "NaClSetUpBootstrapChannel: secure service address not set\n");
905     return;
906   }
907   if (NULL == nap->service_address) {
908     NaClLog(LOG_FATAL,
909             "NaClSetUpBootstrapChannel: service address not set\n");
910     return;
911   }
912   /*
913    * service_address and service_port are set together.
914    */
915   descs[0] = nap->secure_service_address;
916   descs[1] = nap->service_address;
917
918   hdr.iov = (struct NaClImcMsgIoVec *) NULL;
919   hdr.iov_length = 0;
920   hdr.ndescv = descs;
921   hdr.ndesc_length = NACL_ARRAY_SIZE(descs);
922
923   rv = (*NACL_VTBL(NaClDesc, channel)->SendMsg)((struct NaClDesc *) channel,
924                                                 &hdr, 0);
925   NaClXMutexLock(&nap->mu);
926   if (NULL != nap->bootstrap_channel) {
927     NaClLog(LOG_FATAL,
928             "NaClSetUpBootstrapChannel: cannot have two bootstrap channels\n");
929   }
930   nap->bootstrap_channel = (struct NaClDesc *) channel;
931   channel = NULL;
932   NaClXMutexUnlock(&nap->mu);
933
934   NaClLog(1,
935           ("NaClSetUpBootstrapChannel: descriptor %"NACL_PRIdPTR
936            ", error %"NACL_PRIdS"\n"),
937           (uintptr_t) inherited_desc,
938           rv);
939   if (NACL_FI_ERROR_COND("NaClSetUpBootstrapChannel__SendMsg", 0 != rv)) {
940     NaClLog(LOG_FATAL,
941             "NaClSetUpBootstrapChannel: SendMsg failed, rv = %"NACL_PRIdS"\n",
942             rv);
943   }
944 }
945
946 NaClErrorCode NaClWaitForLoadModuleCommand(struct NaClApp *nap) {
947   NaClErrorCode status;
948
949   NaClLog(4, "NaClWaitForLoadModuleCommand started\n");
950   NaClXMutexLock(&nap->mu);
951   while (nap->module_initialization_state < NACL_MODULE_LOADED) {
952     NaClXCondVarWait(&nap->cv, &nap->mu);
953   }
954   status = nap->module_load_status;
955   NaClXMutexUnlock(&nap->mu);
956   NaClLog(4, "NaClWaitForLoadModuleCommand finished\n");
957
958   return status;
959 }
960
961 NaClErrorCode NaClWaitForLoadModuleStatus(struct NaClApp *nap) {
962   NaClErrorCode status;
963
964   NaClLog(4, "NaClWaitForLoadModuleStatus started\n");
965   NaClXMutexLock(&nap->mu);
966   while (LOAD_STATUS_UNKNOWN == (status = nap->module_load_status)) {
967     NaClXCondVarWait(&nap->cv, &nap->mu);
968   }
969   NaClXMutexUnlock(&nap->mu);
970   NaClLog(4, "NaClWaitForLoadModuleStatus finished\n");
971
972   return status;
973 }
974
975 NaClErrorCode NaClWaitForStartModuleCommand(struct NaClApp *nap) {
976   NaClErrorCode status;
977
978   NaClLog(4, "NaClWaitForStartModuleCommand started\n");
979   NaClXMutexLock(&nap->mu);
980   while (nap->module_initialization_state < NACL_MODULE_STARTED) {
981     NaClXCondVarWait(&nap->cv, &nap->mu);
982   }
983   status = nap->module_load_status;
984   NaClXMutexUnlock(&nap->mu);
985   NaClLog(4, "NaClWaitForStartModuleCommand finished\n");
986
987   return status;
988 }
989
990 void NaClBlockIfCommandChannelExists(struct NaClApp *nap) {
991   if (NULL != nap->secure_service) {
992     for (;;) {
993       struct nacl_abi_timespec req;
994       req.tv_sec = 1000;
995       req.tv_nsec = 0;
996       NaClNanosleep(&req, (struct nacl_abi_timespec *) NULL);
997     }
998   }
999 }
1000
1001 void NaClSecureCommandChannel(struct NaClApp *nap) {
1002   struct NaClSecureService *secure_command_server;
1003
1004   NaClLog(4, "Entered NaClSecureCommandChannel\n");
1005
1006   secure_command_server = (struct NaClSecureService *) malloc(
1007       sizeof *secure_command_server);
1008   if (NACL_FI_ERROR_COND("NaClSecureCommandChannel__malloc",
1009                          NULL == secure_command_server)) {
1010     NaClLog(LOG_FATAL, "Out of memory for secure command channel\n");
1011   }
1012   if (NACL_FI_ERROR_COND("NaClSecureCommandChannel__NaClSecureServiceCtor",
1013                          !NaClSecureServiceCtor(secure_command_server,
1014                                                 nap,
1015                                                 nap->secure_service_port,
1016                                                 nap->secure_service_address))) {
1017     NaClLog(LOG_FATAL, "NaClSecureServiceCtor failed\n");
1018   }
1019   nap->secure_service = secure_command_server;
1020
1021   NaClLog(4, "NaClSecureCommandChannel: starting service thread\n");
1022   if (NACL_FI_ERROR_COND(
1023           "NaClSecureCommandChannel__NaClSimpleServiceStartServiceThread",
1024           !NaClSimpleServiceStartServiceThread((struct NaClSimpleService *)
1025                                                secure_command_server))) {
1026     NaClLog(LOG_FATAL,
1027             "Could not start secure command channel service thread\n");
1028   }
1029
1030   NaClLog(4, "Leaving NaClSecureCommandChannel\n");
1031 }
1032
1033
1034 void NaClAppLoadModule(struct NaClApp   *nap,
1035                        struct NaClDesc  *nexe,
1036                        void             (*load_cb)(void *instance_data,
1037                                                    NaClErrorCode status),
1038                        void             *instance_data) {
1039   NaClErrorCode status = LOAD_OK;
1040
1041   NaClLog(4,
1042           ("Entered NaClAppLoadModule: nap 0x%"NACL_PRIxPTR","
1043            " nexe 0x%"NACL_PRIxPTR"\n"),
1044           (uintptr_t) nap, (uintptr_t) nexe);
1045
1046   /*
1047    * TODO(bsy): consider doing the processing below after sending the
1048    * RPC reply to increase parallelism.
1049    */
1050   NaClXMutexLock(&nap->mu);
1051   if (nap->module_initialization_state != NACL_MODULE_UNINITIALIZED) {
1052     NaClLog(LOG_ERROR, "NaClAppLoadModule: repeated invocation\n");
1053     status = LOAD_DUP_LOAD_MODULE;
1054     NaClXMutexUnlock(&nap->mu);
1055     if (NULL != load_cb) {
1056       (*load_cb)(instance_data, status);
1057     }
1058     return;
1059   }
1060   nap->module_initialization_state = NACL_MODULE_LOADING;
1061   NaClXCondVarBroadcast(&nap->cv);
1062   NaClXMutexUnlock(&nap->mu);
1063
1064   if (NULL != load_cb) {
1065     (*load_cb)(instance_data, status);
1066   }
1067
1068   NaClXMutexLock(&nap->mu);
1069
1070   /*
1071    * Check and possibly mark the nexe binary as OK to attempt memory
1072    * mapping.  We first clear the safe-for-mmap flag -- if we do not
1073    * trust the renderer to really send us a safe-to-mmap descriptor
1074    * and have to query the validation cache, then we also do not want
1075    * to trust the metadata flag value that originated from the
1076    * renderer.
1077    */
1078   NaClDescMarkUnsafeForMmap(nexe);
1079   NaClReplaceDescIfValidationCacheAssertsMappable(&nexe,
1080                                                   nap->validation_cache);
1081
1082   status = NACL_FI_VAL("load_module", NaClErrorCode,
1083                        NaClAppLoadFile(nexe, nap));
1084
1085   if (LOAD_OK != status) {
1086     nap->module_load_status = status;
1087     nap->module_initialization_state = NACL_MODULE_ERROR;
1088     NaClXCondVarBroadcast(&nap->cv);
1089   }
1090   NaClXMutexUnlock(&nap->mu);  /* NaClAppPrepareToLaunch takes mu */
1091   if (LOAD_OK != status) {
1092     return;
1093   }
1094
1095   /***************************************************************************
1096    * TODO(bsy): Remove/merge the code invoking NaClAppPrepareToLaunch
1097    * and NaClGdbHook below with sel_main's main function.  See comment
1098    * there.
1099    ***************************************************************************/
1100
1101   /*
1102    * Finish setting up the NaCl App.
1103    */
1104   status = NaClAppPrepareToLaunch(nap);
1105
1106   NaClXMutexLock(&nap->mu);
1107   nap->module_load_status = status;
1108   nap->module_initialization_state = NACL_MODULE_LOADED;
1109   NaClXCondVarBroadcast(&nap->cv);
1110   NaClXMutexUnlock(&nap->mu);
1111
1112   /* Give debuggers a well known point at which xlate_base is known.  */
1113   NaClGdbHook(nap);
1114 }
1115
1116 int NaClAppRuntimeHostSetup(struct NaClApp                  *nap,
1117                             struct NaClRuntimeHostInterface *host_itf) {
1118   NaClErrorCode status = LOAD_OK;
1119
1120   NaClLog(4,
1121           ("Entered NaClAppRuntimeHostSetup, nap 0x%"NACL_PRIxPTR","
1122            " host_itf 0x%"NACL_PRIxPTR"\n"),
1123           (uintptr_t) nap, (uintptr_t) host_itf);
1124
1125   NaClXMutexLock(&nap->mu);
1126   if (nap->module_initialization_state > NACL_MODULE_STARTING) {
1127     NaClLog(LOG_ERROR, "NaClAppRuntimeHostSetup: too late\n");
1128     status = LOAD_INTERNAL;
1129     goto cleanup_status_mu;
1130   }
1131
1132   nap->runtime_host_interface = (struct NaClRuntimeHostInterface *)
1133       NaClRefCountRef((struct NaClRefCount *) host_itf);
1134
1135   /*
1136    * Hook up runtime host enabled resources, e.g.,
1137    * DEBUG_ONLY:dev://postmessage.  NB: Resources specified by
1138    * file:path should have been taken care of earlier, in
1139    * NaClAppInitialDescriptorHookup.
1140    */
1141   nap->resource_phase = NACL_RESOURCE_PHASE_RUNTIME_HOST;
1142   NaClLog(4, "Processing dev I/O redirection/inheritance from environment\n");
1143   NaClProcessRedirControl(nap);
1144   NaClLog(4, "... done.\n");
1145
1146  cleanup_status_mu:
1147   NaClXMutexUnlock(&nap->mu);
1148   return (int) status;
1149 }
1150
1151 int NaClAppDescQuotaSetup(struct NaClApp                 *nap,
1152                           struct NaClDescQuotaInterface  *quota_itf) {
1153   NaClErrorCode status = LOAD_OK;
1154
1155   NaClLog(4,
1156           ("Entered NaClAppDescQuotaSetup, nap 0x%"NACL_PRIxPTR","
1157            " quota_itf 0x%"NACL_PRIxPTR"\n"),
1158           (uintptr_t) nap, (uintptr_t) quota_itf);
1159
1160   NaClXMutexLock(&nap->mu);
1161   if (nap->module_initialization_state > NACL_MODULE_STARTING) {
1162     NaClLog(LOG_ERROR, "NaClAppDescQuotaSetup: too late\n");
1163     status = LOAD_INTERNAL;
1164     goto cleanup_status_mu;
1165   }
1166
1167   nap->desc_quota_interface = (struct NaClDescQuotaInterface *)
1168     NaClRefCountRef((struct NaClRefCount *) quota_itf);
1169
1170  cleanup_status_mu:
1171   NaClXMutexUnlock(&nap->mu);
1172   return (int) status;
1173 }
1174
1175 void NaClAppStartModule(struct NaClApp  *nap,
1176                         void            (*start_cb)(void *instance_data,
1177                                                     NaClErrorCode status),
1178                         void            *instance_data) {
1179   NaClErrorCode status;
1180
1181   NaClLog(4,
1182           ("Entered NaClAppStartModule, nap 0x%"NACL_PRIxPTR","
1183            " start_cb 0x%"NACL_PRIxPTR", instance_data 0x%"NACL_PRIxPTR"\n"),
1184           (uintptr_t) nap, (uintptr_t) start_cb, (uintptr_t) instance_data);
1185
1186   /*
1187    * When module is loading, we have to block and wait till it is
1188    * fully loaded before we can proceed with start module.
1189    */
1190   NaClXMutexLock(&nap->mu);
1191   if (NACL_MODULE_LOADING == nap->module_initialization_state) {
1192     while (NACL_MODULE_LOADED != nap->module_initialization_state) {
1193       NaClXCondVarWait(&nap->cv, &nap->mu);
1194     }
1195   }
1196   if (nap->module_initialization_state != NACL_MODULE_LOADED) {
1197     if (NACL_MODULE_ERROR == nap->module_initialization_state) {
1198       NaClLog(LOG_ERROR, "NaClAppStartModule: error loading module\n");
1199       status = nap->module_load_status;
1200     } else if (nap->module_initialization_state > NACL_MODULE_LOADED) {
1201       NaClLog(LOG_ERROR, "NaClAppStartModule: repeated invocation\n");
1202       status = LOAD_DUP_START_MODULE;
1203     } else if (nap->module_initialization_state < NACL_MODULE_LOADED) {
1204       NaClLog(LOG_ERROR, "NaClAppStartModule: module not loaded\n");
1205       status = LOAD_INTERNAL;
1206     }
1207     NaClXMutexUnlock(&nap->mu);
1208     if (NULL != start_cb) {
1209       (*start_cb)(instance_data, status);
1210     }
1211     return;
1212   }
1213   status = nap->module_load_status;
1214   nap->module_initialization_state = NACL_MODULE_STARTING;
1215   NaClXCondVarBroadcast(&nap->cv);
1216   NaClXMutexUnlock(&nap->mu);
1217
1218   NaClLog(4, "NaClSecureChannelStartModule: load status %d\n", status);
1219
1220   /*
1221    * We need to invoke the callback now, before we signal the main thread
1222    * to possibly start by setting the state to NACL_MODULE_STARTED, since
1223    * in the case of failure the main thread may quickly exit; if the main
1224    * thread does this before we sent the reply, than the plugin (or any
1225    * other runtime host interface) will be left without an aswer. The
1226    * NACL_MODULE_STARTING state is used as an intermediate state to prevent
1227    * double invocations violating the protocol.
1228    */
1229   if (NULL != start_cb) {
1230     (*start_cb)(instance_data, status);
1231   }
1232
1233   NaClXMutexLock(&nap->mu);
1234   nap->module_initialization_state = NACL_MODULE_STARTED;
1235   NaClXCondVarBroadcast(&nap->cv);
1236   NaClXMutexUnlock(&nap->mu);
1237 }
1238
1239 void NaClAppShutdown(struct NaClApp     *nap,
1240                      int                exit_status) {
1241   NaClLog(4, "NaClAppShutdown: nap 0x%"NACL_PRIxPTR
1242           ", exit_status %d\n", (uintptr_t) nap, exit_status);
1243
1244   NaClXMutexLock(&nap->mu);
1245   nap->exit_status = exit_status;
1246   NaClXMutexUnlock(&nap->mu);
1247   if (NULL != nap->debug_stub_callbacks) {
1248     nap->debug_stub_callbacks->process_exit_hook();
1249   }
1250   NaClExit(0);
1251 }
1252
1253 /*
1254  * It is fine to have multiple I/O operations read from memory in Write
1255  * or SendMsg like operations.
1256  */
1257 void NaClVmIoWillStart(struct NaClApp *nap,
1258                        uint32_t addr_first_usr,
1259                        uint32_t addr_last_usr) {
1260   NaClXMutexLock(&nap->mu);
1261   (*nap->mem_io_regions->vtbl->AddInterval)(nap->mem_io_regions,
1262                                             addr_first_usr,
1263                                             addr_last_usr);
1264   NaClXMutexUnlock(&nap->mu);
1265 }
1266
1267
1268 void NaClVmIoHasEnded(struct NaClApp *nap,
1269                       uint32_t addr_first_usr,
1270                       uint32_t addr_last_usr) {
1271   NaClXMutexLock(&nap->mu);
1272   (*nap->mem_io_regions->vtbl->RemoveInterval)(nap->mem_io_regions,
1273                                                addr_first_usr,
1274                                                addr_last_usr);
1275   NaClXMutexUnlock(&nap->mu);
1276 }
1277
1278 void NaClVmIoPendingCheck_mu(struct NaClApp *nap,
1279                              uint32_t addr_first_usr,
1280                              uint32_t addr_last_usr) {
1281   if ((*nap->mem_io_regions->vtbl->OverlapsWith)(nap->mem_io_regions,
1282                                                  addr_first_usr,
1283                                                  addr_last_usr)) {
1284     NaClLog(LOG_FATAL,
1285             "NaClVmIoWillStart: program mem write race detected. ABORTING\n");
1286   }
1287 }
1288
1289 /*
1290  * GDB's canonical overlay managment routine.
1291  * We need its symbol in the symbol table so don't inline it.
1292  * TODO(dje): add some explanation for the non-GDB person.
1293  */
1294 #if NACL_WINDOWS
1295 __declspec(dllexport noinline)
1296 #endif
1297 #ifdef __GNUC__
1298 __attribute__((noinline))
1299 #endif
1300 void _ovly_debug_event (void) {
1301 #ifdef __GNUC__
1302   /*
1303    * The asm volatile is here as instructed by the GCC docs.
1304    * It's not enough to declare a function noinline.
1305    * GCC will still look inside the function to see if it's worth calling.
1306    */
1307   __asm__ volatile ("");
1308 #elif NACL_WINDOWS
1309   /*
1310    * Visual Studio inlines empty functions even with noinline attribute,
1311    * so we need a compile memory barrier to make this function not to be
1312    * inlined. Also, it guarantees that nacl_global_xlate_base initialization
1313    * is not reordered. This is important for gdb since it sets breakpoint on
1314    * this function and reads nacl_global_xlate_base value.
1315    */
1316   _ReadWriteBarrier();
1317 #endif
1318 }
1319
1320 static void StopForDebuggerInit (uintptr_t mem_start) {
1321   /* Put xlate_base in a place where gdb can find it.  */
1322   nacl_global_xlate_base = mem_start;
1323
1324   NaClSandboxMemoryStartForValgrind(mem_start);
1325
1326   _ovly_debug_event();
1327 }
1328
1329 void NaClGdbHook(struct NaClApp const *nap) {
1330   StopForDebuggerInit(nap->mem_start);
1331 }