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