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