1ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch/* Copyright (c) 2013 The Chromium Authors. All rights reserved.
2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * Use of this source code is governed by a BSD-style license that can be
3ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * found in the LICENSE file. */
4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <assert.h>
6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <inttypes.h>
7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <pthread.h>
8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <stdio.h>
9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <stdlib.h>
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <string.h>
11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <sys/mman.h>
12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <unistd.h>
13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#ifdef __GLIBC__
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <elf.h>
16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <link.h>
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif  /* __GLIBC__ */
18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "irt.h"
20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "nacl/nacl_exception.h"
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "error_handling/error_handling.h"
23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "error_handling/string_stream.h"
24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#define PAGE_CHUNK_SIZE (64 * 1024)
27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#define PAGE_CHUNK_MASK (PAGE_CHUNK_SIZE - 1)
28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#define STACK_SIZE_MIN (PAGE_CHUNK_SIZE * 4)
29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#define MAX_FRAME_SIZE (10 * 1024)
31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#define MAX_FRAME_CAP 128
32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)static pthread_key_t s_eh_stack_info_key;
34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)static EHJsonHandler s_eh_json_callback = NULL;
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)static int s_eh_exception_enabled = 0;
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)static struct nacl_irt_exception_handling s_exception_handling;
37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)typedef struct {
40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  void* stack;
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  size_t size;
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} EHStackInfo;
43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)static uintptr_t EHReadPointer(uintptr_t offset) {
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return *((uintptr_t*) offset);
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)static void EHPrintArch(sstream_t* ss, struct NaClExceptionContext* context) {
49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#if defined(__x86_64__)
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ssprintf(ss, "\"arch\": \"x86_64\",\n");
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#elif defined(__i386__)
52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ssprintf(ss, "\"arch\": \"x86_32\",\n");
53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#elif defined(__arm__)
54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ssprintf(ss, "\"arch\": \"arm\",\n");
55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#elif defined(__mips__)
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ssprintf(ss, "\"arch\": \"mips\",\n");
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#else
58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#error Unknown ARCH
59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif
60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)static void EHPrintSegments(sstream_t* ss,
63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            struct NaClExceptionContext* context) {
64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ssprintf(ss, "\"segments\": [");
65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ssprintf(ss, "],\n");
66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)static void EHPrintFrame(sstream_t* ss, EHFrame* frame) {
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  uintptr_t start;
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  uintptr_t i;
71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ssprintf(ss, "{\n");
73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ssprintf(ss, "\"frame_ptr\": %u,\n", frame->frame_ptr);
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ssprintf(ss, "\"prog_ctr\": %u,\n", frame->prog_ctr);
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ssprintf(ss, "\"data\": [\n");
76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#if defined(__x86_64__)
78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  start = frame->frame_ptr + 8;
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#else
80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  start = frame->frame_ptr + 16;
81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif
82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  /* Capture the stack, no mare than 128 bytes to keep the size sane. */
83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (i = start; i < frame->next_ptr && i - start < MAX_FRAME_CAP; i += 4) {
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (i != start) {
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ssprintf(ss, ",");
86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    ssprintf(ss, "%u\n", EHReadPointer(i));
88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ssprintf(ss, "]\n}\n");
90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)static void EHPrintMainContext(sstream_t* ss,
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                               struct NaClExceptionContext* context) {
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  struct NaClExceptionPortableContext* portable_context =
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      nacl_exception_context_get_portable(context);
97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ssprintf(ss, "\"handler\": {\n");
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ssprintf(ss, "\"prog_ctr\": %u,\n", portable_context->prog_ctr);
99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ssprintf(ss, "\"stack_ptr\": %u,\n", portable_context->stack_ptr);
100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ssprintf(ss, "\"frame_ptr\": %u\n", portable_context->frame_ptr);
101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ssprintf(ss, "},\n");
102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)int EHGetTopFrame(sstream_t* ss, struct NaClExceptionContext* context,
106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                  EHFrame* frame) {
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  struct NaClExceptionPortableContext* portable_context =
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      nacl_exception_context_get_portable(context);
109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  frame->prog_ctr = portable_context->prog_ctr;
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  frame->frame_ptr = portable_context->frame_ptr;
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  frame->next_ptr = EHReadPointer(portable_context->frame_ptr);
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return 1;
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)int EHUnwindFrame(EHFrame* frame) {
118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  uintptr_t frame_ptr;
119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  uintptr_t next;
120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Verify the current frame
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (NULL == frame) return 0;
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  frame_ptr = frame->frame_ptr;
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  next = frame->next_ptr;
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Abort if done or unwind moves us in the wrong direction
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (next <= frame_ptr || next == 0) return 0;
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Abort if frame is > 10K
131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (next - frame_ptr > MAX_FRAME_SIZE) return 0;
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Unwind the frame
134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  frame->frame_ptr = next;
135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  frame->next_ptr = EHReadPointer(frame->frame_ptr);
136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#if defined(__x86_64__)
137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  frame->prog_ctr = EHReadPointer(frame_ptr + 8);
138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#else
139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  frame->prog_ctr = EHReadPointer(frame_ptr + 4);
140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif
141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return 1;
142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)static void EHStackInfoDestructor(void *arg) {
146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EHStackInfo* info = (EHStackInfo*) arg;
147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (info) {
149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    munmap(info->stack, info->size);
150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  free(info);
152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void EHDefaultJsonHandler(struct NaClExceptionContext* context) {
156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (s_eh_json_callback) {
157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    EHFrame frame;
158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    sstream_t ss;
159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    ssinit(&ss);
160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    ssprintf(&ss, "{\n");
162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    EHPrintArch(&ss, context);
163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    EHPrintSegments(&ss, context);
164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    EHPrintMainContext(&ss, context);
165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    EHGetTopFrame(&ss, context, &frame);
167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int first = 1;
168c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    ssprintf(&ss, "\"frames\": [\n");
170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    do {
171c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (!first) ssprintf(&ss, ",");
172c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      EHPrintFrame(&ss, &frame);
173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      first = 0;
174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    } while (EHUnwindFrame(&frame));
175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    /* End frame LIST and context DICT */
177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    ssprintf(&ss, "]\n}\n");
178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    s_eh_json_callback(ss.data);
179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    ssfree(&ss);
181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    while(1) sleep(9999);
182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
186c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void EHRequestExceptionsRaw(EHRawHandler callback) {
187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  size_t interface_size = sizeof(s_exception_handling);
188c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (s_eh_exception_enabled) {
189c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    fprintf(stderr, "ERROR: EHInit already initialized.\n");
190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (NULL == callback) {
193c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    fprintf(stderr, "ERROR: EHInit called with NULL callback.\n");
194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
195c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
196c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
197c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  /* Expect an exact match on the interface structure size. */
198c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (nacl_interface_query(NACL_IRT_EXCEPTION_HANDLING_v0_1,
199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                           &s_exception_handling,
200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                           interface_size) != interface_size) {
201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    fprintf(stderr, "ERROR: EHInit failed nacl_interface_query\n");
202c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
203c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
204c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (s_exception_handling.exception_handler(callback, NULL) != 0) {
206c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    fprintf(stderr, "ERROR: EHInit failed to install exception_handler\n");
207c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
208c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
209c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
210c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  s_eh_exception_enabled = 1;
211c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
212c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Create a TLS key for storing per thread stack info
213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  pthread_key_create(&s_eh_stack_info_key, EHStackInfoDestructor);
214c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
215c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
216c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
217c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void *EHRequestExceptionStackOnThread(size_t stack_size) {
218c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  void* stack;
219c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  void* guard;
220c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EHStackInfo* stack_info;
221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Set the stack size
223c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  stack_size = (stack_size + PAGE_CHUNK_MASK) & PAGE_CHUNK_MASK;
224c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (stack_size < STACK_SIZE_MIN) stack_size = STACK_SIZE_MIN;
225c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
226c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Allocate stack + guard page
227c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  stack = mmap(NULL, stack_size + PAGE_CHUNK_SIZE,
228c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
229c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (MAP_FAILED == stack) return MAP_FAILED;
230c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
231c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Remap to mprotect which may not be available
232c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  guard = mmap(stack, PAGE_CHUNK_SIZE,
233c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
234c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (guard != stack) {
235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    fprintf(stderr, "WARNING: Failed to add guard page for alt stack.\n");
236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
238c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!s_exception_handling.exception_stack(stack, stack_size)) {
239c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    fprintf(stderr, "ERROR: Failed to assign stack.\n");
240c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    munmap(stack, stack_size);
241c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return MAP_FAILED;
242c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Allocate stack tracking information for this thread
245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  stack_info = (EHStackInfo*) malloc(sizeof(EHStackInfo));
246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  stack_info->stack = stack;
247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  stack_info->size = stack_size + PAGE_CHUNK_SIZE;
248c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  pthread_setspecific(s_eh_stack_info_key, stack_info);
249c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return stack;
250c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
251c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
252c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void EHRequestExceptionsJson(EHJsonHandler callback) {
254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (NULL == callback) return;
255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EHRequestExceptionsRaw(EHDefaultJsonHandler);
257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (s_eh_exception_enabled) s_eh_json_callback = callback;
258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)int EHHanderInstalled() {
262c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return s_eh_exception_enabled;
263ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
264