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