LCOV - code coverage report
Current view: directory - src/trusted/service_runtime/osx - mach_exception_handler.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 132 57 43.2 %
Date: 2012-02-16 Functions: 0 0 -

       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 "native_client/src/trusted/service_runtime/osx/mach_exception_handler.h"
       8                 : 
       9                 : #include <mach/mach.h>
      10                 : #include <mach/mach_vm.h>
      11                 : #include <mach/thread_status.h>
      12                 : #include <pthread.h>
      13                 : #include <stdio.h>
      14                 : #include <stdlib.h>
      15                 : 
      16                 : #include "gen/native_client/src/trusted/service_runtime/nacl_exc.h"
      17                 : #include "native_client/src/include/nacl_macros.h"
      18                 : #include "native_client/src/include/portability.h"
      19                 : #include "native_client/src/shared/platform/nacl_check.h"
      20                 : #include "native_client/src/shared/platform/nacl_log.h"
      21                 : #include "native_client/src/trusted/service_runtime/arch/sel_ldr_arch.h"
      22                 : #include "native_client/src/trusted/service_runtime/nacl_app.h"
      23                 : #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
      24                 : #include "native_client/src/trusted/service_runtime/nacl_config.h"
      25                 : #include "native_client/src/trusted/service_runtime/nacl_globals.h"
      26                 : #include "native_client/src/trusted/service_runtime/nacl_switch_to_app.h"
      27                 : #include "native_client/src/trusted/service_runtime/sel_ldr.h"
      28                 : #include "native_client/src/trusted/service_runtime/sel_rt.h"
      29                 : 
      30                 : /* Only handle x86_32 for now. */
      31                 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
      32                 : 
      33                 : 
      34                 : /*
      35                 :  * MIG generated message pump from /usr/include/mach/exc.defs
      36                 :  * Tweaked to place in an isolated namespace.
      37                 :  */
      38                 : boolean_t nacl_exc_server(
      39                 :     mach_msg_header_t *InHeadP,
      40                 :     mach_msg_header_t *OutHeadP);
      41                 : 
      42                 : 
      43                 : /* Exception types to intercept. */
      44                 : #define NACL_MACH_EXCEPTION_MASK EXC_MASK_BAD_ACCESS
      45                 : /*
      46                 :  * TODO(bradnelson): eventually consider these too:
      47                 :  *     EXC_MASK_BAD_INSTRUCTION
      48                 :  *     EXC_MASK_ARITHMETIC
      49                 :  *     EXC_MASK_BREAKPOINT
      50                 :  */
      51                 : 
      52                 : /* TODO(bradnelson): merge this into a common location. */
      53                 : struct ExceptionFrame {
      54                 :   uint32_t return_addr;
      55                 :   uint32_t prog_ctr;
      56                 :   uint32_t stack_ptr;
      57                 : };
      58                 : 
      59                 : struct MachExceptionParameters {
      60                 :   mach_msg_type_number_t count;
      61                 :   exception_mask_t masks[EXC_TYPES_COUNT];
      62                 :   mach_port_t ports[EXC_TYPES_COUNT];
      63                 :   exception_behavior_t behaviors[EXC_TYPES_COUNT];
      64                 :   thread_state_flavor_t flavors[EXC_TYPES_COUNT];
      65                 : };
      66                 : 
      67                 : struct MachExceptionHandlerData {
      68                 :   struct MachExceptionParameters old_ports;
      69                 :   mach_port_t exception_port;
      70                 : };
      71                 : 
      72                 : /*
      73                 :  * This is global because MIG does not provide a mechanism to associate
      74                 :  * user data with a handler. We could 'sed' the output, but that might be
      75                 :  * brittle. This is moot as the handler is task wide. Revisit if we switch to
      76                 :  * a per-thread handler.
      77                 :  */
      78                 : static struct MachExceptionHandlerData *g_MachExceptionHandlerData = 0;
      79                 : 
      80                 : 
      81                 : static int HandleException(mach_port_t thread_port,
      82               1 :                            exception_type_t exception, int *is_untrusted) {
      83                 :   mach_msg_type_number_t size;
      84                 :   x86_thread_state_t regs;
      85                 :   kern_return_t result;
      86               1 :   uint16_t trusted_cs = NaClGetGlobalCs();
      87               1 :   uint16_t trusted_ds = NaClGetGlobalDs();
      88                 :   uint32_t nacl_thread_index;
      89                 :   struct NaClApp *nap;
      90                 :   struct NaClAppThread *natp;
      91                 :   struct ExceptionFrame frame;
      92                 :   uintptr_t frame_addr_user;
      93                 :   uintptr_t frame_addr_sys;
      94                 : 
      95                 :   /* Assume untrusted crash until we know otherwise. */
      96               1 :   *is_untrusted = TRUE;
      97                 : 
      98                 :   /* Capture the register state of the 'excepting' thread. */
      99               1 :   size = sizeof(regs) / sizeof(natural_t);
     100               1 :   result = thread_get_state(thread_port, x86_THREAD_STATE,
     101                 :                             (void *) &regs, &size);
     102               1 :   if (result != KERN_SUCCESS) {
     103               0 :     return 0;
     104                 :   }
     105                 : 
     106                 :   /*
     107                 :    * If trusted_cs is 0 (which is not a usable segment selector), the
     108                 :    * sandbox has not been initialised yet, so there can be no untrusted
     109                 :    * code running.
     110                 :    */
     111               1 :   if (trusted_cs == 0) {
     112               1 :     *is_untrusted = FALSE;
     113               1 :     return 0;
     114                 :   }
     115                 : 
     116                 :   /*
     117                 :    * If the current code segment is the trusted one, we aren't in the
     118                 :    * sandbox.
     119                 :    * TODO(bradnelson): This makes the potentially false assumption that cs is
     120                 :    *     the last thing to change when switching into untrusted code. We need
     121                 :    *     tests to vet this.
     122                 :    */
     123               0 :   if (regs.uts.ts32.__cs == trusted_cs) {
     124               0 :     *is_untrusted = FALSE;
     125               0 :     return 0;
     126                 :   }
     127                 : 
     128                 :   /* Ignore all but bad accesses for now. */
     129               0 :   if (exception != EXC_BAD_ACCESS) {
     130               0 :     return 0;
     131                 :   }
     132                 : 
     133                 :   /*
     134                 :    * We can get the thread index from the segment selector used for TLS
     135                 :    * from %gs >> 3.
     136                 :    * TODO(bradnelson): Migrate that knowledge to a single shared location.
     137                 :    */
     138               0 :   nacl_thread_index = regs.uts.ts32.__gs >> 3;
     139               0 :   natp = nacl_thread[nacl_thread_index];
     140               0 :   nap = natp->nap;
     141                 : 
     142                 :   /* Don't handle it if the exception flag is set. */
     143               0 :   if (natp->user.exception_flag) {
     144               0 :     return 0;
     145                 :   }
     146                 :   /* Set the flag. */
     147               0 :   natp->user.exception_flag = 1;
     148                 : 
     149                 :   /* Don't handle if no exception handler is set. */
     150               0 :   if (nap->exception_handler == 0) {
     151               0 :     return 0;
     152                 :   }
     153                 : 
     154                 :   /* Get location of exception stack frame. */
     155               0 :   if (natp->user.exception_stack) {
     156               0 :     frame_addr_user = natp->user.exception_stack;
     157                 :   } else {
     158                 :     /* If not set default to user stack. */
     159               0 :     frame_addr_user = regs.uts.ts32.__esp;
     160                 :   }
     161                 : 
     162                 :   /* Align stack frame properly. */
     163               0 :   frame_addr_user -= sizeof(struct ExceptionFrame) - NACL_STACK_PAD_BELOW_ALIGN;
     164               0 :   frame_addr_user &= ~NACL_STACK_ALIGN_MASK;
     165               0 :   frame_addr_user -= NACL_STACK_PAD_BELOW_ALIGN;
     166                 : 
     167                 :   /* Convert from user to system space. */
     168               0 :   frame_addr_sys = NaClUserToSysAddrRange(
     169                 :       nap, frame_addr_user, sizeof(struct ExceptionFrame));
     170               0 :   if (frame_addr_sys == kNaClBadAddress) {
     171               0 :     return 0;
     172                 :   }
     173                 : 
     174                 :   /* Set up the stack frame for the handler invocation. */
     175               0 :   frame.return_addr = 0;
     176               0 :   frame.prog_ctr = regs.uts.ts32.__eip;
     177               0 :   frame.stack_ptr = regs.uts.ts32.__esp;
     178                 : 
     179                 :   /*
     180                 :    * Write the stack frame into untrusted address space.  We do not
     181                 :    * write to the memory directly because that will fault if the
     182                 :    * destination location is not writable.  Faulting is OK for NaCl
     183                 :    * syscalls, but here we do not want to trigger an exception while
     184                 :    * in the exception handler.  The overhead of using a Mach system
     185                 :    * call to write to memory is acceptable here.
     186                 :    */
     187               0 :   result = mach_vm_write(mach_task_self(), frame_addr_sys,
     188                 :                          (uintptr_t) &frame, sizeof(frame));
     189               0 :   if (result != KERN_SUCCESS) {
     190               0 :     return 0;
     191                 :   }
     192                 : 
     193                 :   /* Set up thread context to resume at handler. */
     194               0 :   natp->user.new_prog_ctr = nap->exception_handler;
     195               0 :   natp->user.stack_ptr.ptr_32.ptr = frame_addr_user;
     196                 :   /*
     197                 :    * Preserve %ebp for consistency with x86-32 Linux and Windows, and
     198                 :    * because it is needed for doing stack backtraces.
     199                 :    * TODO(mseaborn): Save %ebp in the exception frame rather than
     200                 :    * preserving it.
     201                 :    */
     202               0 :   natp->user.frame_ptr.ptr_32.ptr = regs.uts.ts32.__ebp;
     203                 : 
     204                 :   /*
     205                 :    * Put registers in right place to land at NaClSwitchNoSSEViaECX
     206                 :    * This is required because:
     207                 :    *   - For an unknown reason thread_set_state resets %cs to the default
     208                 :    *     value, even when set to something else, in current XNU versions.
     209                 :    *   - An examination of the XNU sources indicates
     210                 :    *     that setting the code which state the thread state resets
     211                 :    *     %cs, %ds, %es, %ss to their default values in some early versions.
     212                 :    *     (For instance: xnu-792.6.22/osfmk/i386/pcb.c:616)
     213                 :    * This precludes going directly to the untrusted handler.
     214                 :    * Instead we call a variant of NaClSwitchNoSSE which takes a pointer
     215                 :    * to the thread user context in %ecx.
     216                 :    */
     217               0 :   regs.uts.ts32.__eip = (uint32_t) &NaClSwitchNoSSEViaECX;
     218               0 :   regs.uts.ts32.__cs = trusted_cs;
     219               0 :   regs.uts.ts32.__ecx = (uint32_t) &natp->user;
     220               0 :   regs.uts.ts32.__ds = trusted_ds;
     221               0 :   regs.uts.ts32.__es = trusted_ds;  /* just for good measure */
     222               0 :   regs.uts.ts32.__ss = trusted_ds;  /* just for good measure */
     223               0 :   regs.uts.ts32.__eflags &= ~NACL_X86_DIRECTION_FLAG;
     224               0 :   result = thread_set_state(thread_port, x86_THREAD_STATE,
     225                 :                             (void *) &regs, size);
     226               0 :   if (result != KERN_SUCCESS) {
     227               0 :     return 0;
     228                 :   }
     229                 : 
     230                 :   /* Return success, and resume the thread. */
     231               0 :   return 1;
     232                 : }
     233                 : 
     234                 : 
     235                 : static kern_return_t ForwardException(
     236                 :     struct MachExceptionHandlerData *data,
     237                 :     mach_port_t thread,
     238                 :     mach_port_t task,
     239                 :     exception_type_t exception,
     240                 :     exception_data_t code,
     241               1 :     mach_msg_type_number_t code_count) {
     242                 :   unsigned int i;
     243                 :   mach_port_t target_port;
     244                 :   exception_behavior_t target_behavior;
     245                 : 
     246                 :   /* Find a port with a mask matching this exception to pass it on to. */
     247               1 :   for (i = 0; i < data->old_ports.count; ++i) {
     248               1 :     if (data->old_ports.masks[i] & (1 << exception)) {
     249               1 :       break;
     250                 :     }
     251                 :   }
     252               1 :   if (i == data->old_ports.count) {
     253               0 :     return KERN_FAILURE;
     254                 :   }
     255               1 :   target_port = data->old_ports.ports[i];
     256               1 :   target_behavior = data->old_ports.behaviors[i];
     257                 : 
     258                 :   /*
     259                 :    * By default a null exception port is registered.
     260                 :    * As it is unclear how to forward to this, we should just fail.
     261                 :    */
     262               1 :   if (target_port == 0) {
     263               0 :     return KERN_FAILURE;
     264                 :   }
     265                 : 
     266                 :   /*
     267                 :    * Only support EXCEPTION_DEFAULT, as we only plan to inter-operate with
     268                 :    * Breakpad for now.
     269                 :    */
     270               1 :   CHECK(target_behavior == EXCEPTION_DEFAULT);
     271                 : 
     272                 :   /* Forward the exception. */
     273               1 :   return exception_raise(target_port, thread, task, exception,
     274                 :                          code, code_count);
     275                 : }
     276                 : 
     277                 : 
     278                 : kern_return_t nacl_catch_exception_raise(
     279                 :     mach_port_t exception_port,
     280                 :     mach_port_t thread,
     281                 :     mach_port_t task,
     282                 :     exception_type_t exception,
     283                 :     exception_data_t code,
     284               1 :     mach_msg_type_number_t code_count) {
     285                 :   int is_untrusted;
     286                 : 
     287                 :   UNREFERENCED_PARAMETER(exception_port);
     288                 : 
     289                 :   /* Check if we want to handle this exception. */
     290               1 :   if (HandleException(thread, exception, &is_untrusted)) {
     291               0 :     return KERN_SUCCESS;
     292                 :   }
     293                 : 
     294                 :   /*
     295                 :    * Don't forward if the crash is untrusted, but unhandled.
     296                 :    * (As we don't want things like Breakpad handling the crash.)
     297                 :    */
     298               1 :   if (is_untrusted) {
     299               0 :     return KERN_FAILURE;
     300                 :   }
     301                 : 
     302                 :   /* Forward on the exception to the old set of ports. */
     303               1 :   return ForwardException(
     304                 :       g_MachExceptionHandlerData, thread, task, exception, code, code_count);
     305                 : }
     306                 : 
     307                 : kern_return_t nacl_catch_exception_raise_state(
     308                 :     mach_port_t exception_port,
     309                 :     exception_type_t exception,
     310                 :     const exception_data_t code,
     311                 :     mach_msg_type_number_t code_count,
     312                 :     int *flavor,
     313                 :     const thread_state_t old_state,
     314                 :     mach_msg_type_number_t old_state_count,
     315                 :     thread_state_t new_state,
     316               0 :     mach_msg_type_number_t *new_state_count) {
     317                 :   /* MIG generated code expects this, but should never be called. */
     318                 :   UNREFERENCED_PARAMETER(exception_port);
     319                 :   UNREFERENCED_PARAMETER(exception);
     320                 :   UNREFERENCED_PARAMETER(code);
     321                 :   UNREFERENCED_PARAMETER(code_count);
     322                 :   UNREFERENCED_PARAMETER(flavor);
     323                 :   UNREFERENCED_PARAMETER(old_state);
     324                 :   UNREFERENCED_PARAMETER(old_state_count);
     325                 :   UNREFERENCED_PARAMETER(new_state);
     326                 :   UNREFERENCED_PARAMETER(new_state_count);
     327               0 :   NaClLog(LOG_FATAL, "nacl_catch_exception_raise_state: "
     328                 :                      "Unrequested message received.\n");
     329               0 :   return KERN_FAILURE;
     330                 : }
     331                 : 
     332                 : kern_return_t nacl_catch_exception_raise_state_identity (
     333                 :         mach_port_t exception_port,
     334                 :         mach_port_t thread,
     335                 :         mach_port_t task,
     336                 :         exception_type_t exception,
     337                 :         exception_data_t code,
     338                 :         mach_msg_type_number_t code_count,
     339                 :         int *flavor,
     340                 :         thread_state_t old_state,
     341                 :         mach_msg_type_number_t old_state_count,
     342                 :         thread_state_t new_state,
     343               0 :         mach_msg_type_number_t *new_state_count) {
     344                 :   /* MIG generated code expects this, but should never be called. */
     345                 :   UNREFERENCED_PARAMETER(exception_port);
     346                 :   UNREFERENCED_PARAMETER(thread);
     347                 :   UNREFERENCED_PARAMETER(task);
     348                 :   UNREFERENCED_PARAMETER(exception);
     349                 :   UNREFERENCED_PARAMETER(code);
     350                 :   UNREFERENCED_PARAMETER(code_count);
     351                 :   UNREFERENCED_PARAMETER(flavor);
     352                 :   UNREFERENCED_PARAMETER(old_state);
     353                 :   UNREFERENCED_PARAMETER(old_state_count);
     354                 :   UNREFERENCED_PARAMETER(new_state);
     355                 :   UNREFERENCED_PARAMETER(new_state_count);
     356               0 :   NaClLog(LOG_FATAL, "nacl_catch_exception_raise_state_identity: "
     357                 :                      "Unrequested message received.\n");
     358               0 :   return KERN_FAILURE;
     359                 : }
     360                 : 
     361               1 : static void *MachExceptionHandlerThread(void *arg) {
     362                 :   struct MachExceptionHandlerData *data =
     363               1 :       (struct MachExceptionHandlerData *) arg;
     364                 :   kern_return_t result;
     365                 :   /* Have space for a fairly large mach messages. */
     366                 :   struct {
     367                 :     mach_msg_header_t header;
     368                 :     mach_msg_body_t body;
     369                 :     char padding[1024];
     370                 :   } request;
     371                 :   struct {
     372                 :     mach_msg_header_t header;
     373                 :     mach_msg_body_t body;
     374                 :     mig_reply_error_t reply_error;
     375                 :     mach_msg_trailer_t trailer;
     376                 :   } reply;
     377                 : 
     378                 :   for (;;) {
     379               1 :     result = mach_msg(&request.header, MACH_RCV_MSG | MACH_RCV_LARGE, 0,
     380                 :                       sizeof(request), data->exception_port,
     381                 :                       MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
     382               1 :     if (result != MACH_MSG_SUCCESS) {
     383               0 :       goto failure;
     384                 :     }
     385               1 :     if (!nacl_exc_server(&request.header, &reply.header)) {
     386               0 :       goto failure;
     387                 :     }
     388               0 :     result = mach_msg(&reply.header, MACH_SEND_MSG,
     389                 :                       reply.header.msgh_size, 0,
     390                 :                       MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
     391               0 :     if (result != MACH_MSG_SUCCESS) {
     392               0 :       goto failure;
     393                 :     }
     394               0 :   }
     395                 : 
     396               0 : failure:
     397               0 :   free(data);
     398                 : 
     399               0 :   return 0;
     400                 : }
     401                 : 
     402               1 : static int InstallHandler(struct MachExceptionHandlerData *data) {
     403                 :   kern_return_t result;
     404               1 :   mach_port_t current_task = mach_task_self();
     405                 :   unsigned int i;
     406                 : 
     407                 :   /* Capture old handler info. */
     408               1 :   data->old_ports.count = EXC_TYPES_COUNT;
     409               1 :   result = task_get_exception_ports(current_task, NACL_MACH_EXCEPTION_MASK,
     410                 :                                     data->old_ports.masks,
     411                 :                                     &data->old_ports.count,
     412                 :                                     data->old_ports.ports,
     413                 :                                     data->old_ports.behaviors,
     414                 :                                     data->old_ports.flavors);
     415               1 :   if (result != KERN_SUCCESS) {
     416               0 :     return result;
     417                 :   }
     418                 : 
     419                 :   /*
     420                 :    * We only handle forwarding of the EXCEPTION_DEFAULT behavior (all that
     421                 :    * Breakpad needs). Check that all old handlers are either of this behavior
     422                 :    * type or null.
     423                 :    *
     424                 :    * NOTE: Ideally we might also require a particular behavior for null
     425                 :    * exception ports. Unfortunately, testing indicates that while on
     426                 :    * OSX 10.6 / 10.7 the behavior for such a null port is set to 0,
     427                 :    * on OSX 10.5 it is set to 0x803fe956 (on a given run).
     428                 :    * As tasks inherit exception ports from their parents, this may be
     429                 :    * an uninitialized value carried along from a parent.
     430                 :    * http://opensource.apple.com/source/xnu/xnu-1228.0.2/osfmk/kern/ipc_tt.c
     431                 :    * For now, we will ignore the behavior when the port is null.
     432                 :    */
     433               2 :   for (i = 0; i < data->old_ports.count; ++i) {
     434               1 :     CHECK(data->old_ports.behaviors[i] == EXCEPTION_DEFAULT ||
     435                 :           data->old_ports.ports[i] == 0);
     436                 :   }
     437                 : 
     438                 :   /* TODO(bradnelson): decide if we should set the exception port per thread. */
     439                 :   /* Direct all task exceptions to new exception port. */
     440               1 :   result = task_set_exception_ports(current_task, NACL_MACH_EXCEPTION_MASK,
     441                 :                                     data->exception_port, EXCEPTION_DEFAULT,
     442                 :                                     THREAD_STATE_NONE);
     443               1 :   if (result != KERN_SUCCESS) {
     444               0 :     return result;
     445                 :   }
     446                 : 
     447               1 :   return KERN_SUCCESS;
     448                 : }
     449                 : 
     450               1 : int NaClInterceptMachExceptions(void) {
     451                 :   struct MachExceptionHandlerData *data;
     452                 :   kern_return_t result;
     453                 :   mach_port_t current_task;
     454                 :   pthread_attr_t attr;
     455                 :   int thread_result;
     456                 :   pthread_t exception_handler_thread;
     457                 : 
     458               1 :   current_task = mach_task_self();
     459                 : 
     460                 :   /* Allocate structure to share with exception handler thread. */
     461               1 :   data = (struct MachExceptionHandlerData *) calloc(1, sizeof(*data));
     462               1 :   if (data == NULL) {
     463               0 :     goto failure;
     464                 :   }
     465               1 :   g_MachExceptionHandlerData = data;
     466               1 :   data->exception_port = MACH_PORT_NULL;
     467                 : 
     468                 :   /* Allocate port to receive exceptions. */
     469               1 :   result = mach_port_allocate(current_task, MACH_PORT_RIGHT_RECEIVE,
     470                 :                               &data->exception_port);
     471               1 :   if (result != KERN_SUCCESS) {
     472               0 :     goto failure;
     473                 :   }
     474                 : 
     475                 :   /* Add the right to send. */
     476               1 :   result = mach_port_insert_right(current_task,
     477                 :                                   data->exception_port, data->exception_port,
     478                 :                                   MACH_MSG_TYPE_MAKE_SEND);
     479               1 :   if (result != KERN_SUCCESS) {
     480               0 :     goto failure;
     481                 :   }
     482                 : 
     483                 :   /* Install handler. */
     484               1 :   result = InstallHandler(data);
     485               1 :   if (result != KERN_SUCCESS) {
     486               0 :     goto failure;
     487                 :   }
     488                 : 
     489                 :   /* Create handler thread. */
     490               1 :   pthread_attr_init(&attr);
     491               1 :   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
     492               1 :   thread_result = pthread_create(&exception_handler_thread, &attr,
     493                 :                                  &MachExceptionHandlerThread, data);
     494               1 :   pthread_attr_destroy(&attr);
     495               1 :   if (thread_result) {
     496               0 :     goto failure;
     497                 :   }
     498                 : 
     499               1 :   return TRUE;
     500                 : 
     501               0 : failure:
     502               0 :   if (data) {
     503               0 :     if (MACH_PORT_NULL != data->exception_port) {
     504               0 :       mach_port_deallocate(current_task, data->exception_port);
     505                 :     }
     506               0 :     free(data);
     507                 :   }
     508               0 :   return FALSE;
     509                 : }
     510                 : 
     511                 : #else  /* NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32 */
     512                 : 
     513                 : int NaClInterceptMachExceptions(void) {
     514                 :   return FALSE;
     515                 : }
     516                 : 
     517                 : #endif  /* NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32 */

Generated by: LCOV version 1.7