blob: 7c50e3f8989bb584bc70b0ce55db31828c85eda3 [file] [log] [blame]
// Copyright 2017 The Android Open Source Project
//
// This software is licensed under the terms of the GNU General Public
// License version 2, as published by the Free Software Foundation, and
// may be copied, distributed, and modified under those terms.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// This file contains definitions of Mach structs that make it
// easier to handle all sorts of exception flavors/behaviors,
// since we will need to be able to forward any exception that we
// should not handle on to a previous exception handler (i.e.,
// crash reporter or debugger).
#pragma once
#include "android/utils/compiler.h"
// Definitions from:
/* machtest/main.c -- Mac OS X / Mach exception handling prototype
*
* Created by Richard Brooksby on 2013-06-24.
* Copyright 2013 Ravenbrook Limited.
*
* REFERENCES
* http://www.mikeash.com/pyblog/friday-qa-2013-01-11-mach-exception-handlers.html
*/
#include <mach/mach_port.h>
#include <mach/mach_init.h>
#include <mach/task.h>
#include <mach/thread_act.h>
#include <mach/thread_status.h>
#include <mach/mach_error.h>
#include <mach/i386/thread_status.h>
#include <mach/mach_error.h>
#include <mach/exc.h>
ANDROID_BEGIN_HEADER
/* Almost all of this file is architecture-independent, but unfortunately
the Mach headers don't provide architecture neutral symbols for simple
things like thread states. These definitions fix that */
// Only define for x86_64
#define MY_THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT
#define MY_THREAD_STATE_FLAVOR x86_THREAD_STATE64
typedef x86_thread_state64_t my_thread_state_t;
#define MY_IP __rip
/* The Mach headers in /usr/include/mach and the code generated by the Mach
Interface Generator (mig) program are not the truth. In particular, if
you specify your exception behaviour with the MACH_EXCEPTION_CODES flag
then you get a different layout with 64-bit wide exception code and
subcode fields. We want those (so we can get the faulting address on
x86_64) but also we must cope with passing them onwards to other
exception handlers in the debugger or whatever. So we're forced to
define our own copies of these structures. Makes a bit of a nonsense of
having them in /usr/include or mig at all, really.
See http://stackoverflow.com/questions/2824105/handling-mach-exceptions-in-64bit-os-x-application
about MACH_EXCEPTION_CODES. */
/* Structure packing really makes a difference because the code field is
not naturally aligned on 64-bit. */
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t thread;
mach_msg_port_descriptor_t task;
NDR_record_t NDR;
exception_type_t exception;
mach_msg_type_number_t codeCnt;
int64_t code[2];
} __Request__mach_exception_raise_t;
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
exception_type_t exception;
mach_msg_type_number_t codeCnt;
int64_t code[2];
int flavor;
mach_msg_type_number_t old_stateCnt;
natural_t old_state[224];
} __Request__mach_exception_raise_state_t;
typedef struct {
mach_msg_header_t Head;
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t thread;
mach_msg_port_descriptor_t task;
NDR_record_t NDR;
exception_type_t exception;
int codeCnt;
int64_t code[2];
int flavor;
mach_msg_type_number_t old_stateCnt;
natural_t old_state[224];
} __Request__mach_exception_raise_state_identity_t;
// Just define the reply struct for raise_state_identity only for now,
// because that's the only kind of exception we are interested in emitting
// for our purposes.
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
int flavor;
mach_msg_type_number_t new_stateCnt;
natural_t new_state[224];
} __Reply__mach_exception_raise_state_identity_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
typedef union AnyRequest {
mach_msg_header_t Head;
__Request__mach_exception_raise_t raise;
__Request__mach_exception_raise_state_t raise_state;
__Request__mach_exception_raise_state_identity_t raise_state_identity;
} AnyRequest;
/* These are the message IDs that appear in request messages, determined
by experimentation. The replies to these messages are these + 100. */
#define MSG_ID_REQUEST_32 2401
#define MSG_ID_REQUEST_STATE_32 2402
#define MSG_ID_REQUEST_STATE_IDENTITY_32 2403
#define MSG_ID_REQUEST_64 2405
#define MSG_ID_REQUEST_STATE_64 2406
#define MSG_ID_REQUEST_STATE_IDENTITY_64 2407
/* Convert request messages between 32- and 64-bit code code layouts.
May truncate 64-bit codes, of course, but that appears to be what
Mac OS X does. */
#define COPY_COMMON(dst, src, id, code_type) \
do { \
(dst)->Head = (src)->Head; \
(dst)->Head.msgh_id = (id); \
(dst)->Head.msgh_size = sizeof(*dst); \
(dst)->NDR = (src)->NDR; \
(dst)->exception = (src)->exception; \
(dst)->codeCnt = (src)->codeCnt; \
(dst)->code[0] = (code_type)(src)->code[0]; \
(dst)->code[1] = (code_type)(src)->code[1]; \
} while(0)
#define COPY_IDENTITY(dst, src) \
do { \
(dst)->thread = (src)->thread; \
(dst)->task = (src)->task; \
} while(0)
#define COPY_STATE(dst, src, state_flavor, state, state_count) \
do { \
mach_msg_size_t _s; \
(dst)->flavor = (state_flavor); \
(dst)->old_stateCnt = (state_count); \
_s = (dst)->old_stateCnt * sizeof(natural_t); \
assert(_s <= sizeof((dst)->old_state)); \
memcpy((dst)->old_state, (state), _s); \
(dst)->Head.msgh_size = \
offsetof(__Request__mach_exception_raise_state_t, old_state) + _s; \
} while(0)
#define COPY_REQUEST(dst, src, width) \
do { \
COPY_COMMON(dst, src, MSG_ID_REQUEST_##width, __int##width##_t); \
COPY_IDENTITY(dst, src); \
} while(0);
#define COPY_REQUEST_STATE(dst, src, width, state_flavor, state, state_count) \
do { \
COPY_COMMON(dst, src, MSG_ID_REQUEST_STATE_##width, __int##width##_t); \
COPY_STATE(dst, src, state_flavor, state, state_count); \
} while(0)
#define COPY_REQUEST_STATE_IDENTITY(dst, src, width, state_flavor, state, state_count) \
do { \
COPY_COMMON(dst, src, MSG_ID_REQUEST_STATE_IDENTITY_##width, __int##width##_t); \
COPY_IDENTITY(dst, src); \
COPY_STATE(dst, src, state_flavor, state, state_count); \
} while(0)
// For convenience when querying old exception ports, gather all
// the info into a single struct.
typedef struct {
mach_msg_type_number_t count;
exception_mask_t masks[10];
mach_port_name_t ports[10];
exception_behavior_t behaviors[10];
thread_state_flavor_t flavors[10];
} exception_port_settings;
ANDROID_END_HEADER