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