1
0
mirror of https://github.com/beego/bee.git synced 2025-07-01 12:20:17 +00:00

Updated vendor

This commit is contained in:
Ruben Cid
2019-04-15 16:43:01 +02:00
parent 33dd897647
commit da91d50ab8
134 changed files with 4988 additions and 2530 deletions

283
vendor/github.com/go-delve/delve/pkg/proc/native/exc.h generated vendored Normal file
View File

@ -0,0 +1,283 @@
#ifndef _exc_user_
#define _exc_user_
/* Module exc */
#include <string.h>
#include <mach/ndr.h>
#include <mach/boolean.h>
#include <mach/kern_return.h>
#include <mach/notify.h>
#include <mach/mach_types.h>
#include <mach/message.h>
#include <mach/mig_errors.h>
#include <mach/port.h>
/* BEGIN VOUCHER CODE */
#ifndef KERNEL
#if defined(__has_include)
#if __has_include(<mach/mig_voucher_support.h>)
#ifndef USING_VOUCHERS
#define USING_VOUCHERS
#endif
#ifndef __VOUCHER_FORWARD_TYPE_DECLS__
#define __VOUCHER_FORWARD_TYPE_DECLS__
#ifdef __cplusplus
extern "C" {
#endif
extern boolean_t voucher_mach_msg_set(mach_msg_header_t *msg) __attribute__((weak_import));
#ifdef __cplusplus
}
#endif
#endif // __VOUCHER_FORWARD_TYPE_DECLS__
#endif // __has_include(<mach/mach_voucher_types.h>)
#endif // __has_include
#endif // !KERNEL
/* END VOUCHER CODE */
#ifdef AUTOTEST
#ifndef FUNCTION_PTR_T
#define FUNCTION_PTR_T
typedef void (*function_ptr_t)(mach_port_t, char *, mach_msg_type_number_t);
typedef struct {
char *name;
function_ptr_t function;
} function_table_entry;
typedef function_table_entry *function_table_t;
#endif /* FUNCTION_PTR_T */
#endif /* AUTOTEST */
#ifndef exc_MSG_COUNT
#define exc_MSG_COUNT 3
#endif /* exc_MSG_COUNT */
#include <mach/std_types.h>
#include <mach/mig.h>
#include <mach/mig.h>
#include <mach/mach_types.h>
#ifdef __BeforeMigUserHeader
__BeforeMigUserHeader
#endif /* __BeforeMigUserHeader */
#include <sys/cdefs.h>
__BEGIN_DECLS
/* Routine exception_raise */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t exception_raise
(
mach_port_t exception_port,
mach_port_t thread,
mach_port_t task,
exception_type_t exception,
exception_data_t code,
mach_msg_type_number_t codeCnt
);
/* Routine exception_raise_state */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t exception_raise_state
(
mach_port_t exception_port,
exception_type_t exception,
const exception_data_t code,
mach_msg_type_number_t codeCnt,
int *flavor,
const thread_state_t old_state,
mach_msg_type_number_t old_stateCnt,
thread_state_t new_state,
mach_msg_type_number_t *new_stateCnt
);
/* Routine exception_raise_state_identity */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t exception_raise_state_identity
(
mach_port_t exception_port,
mach_port_t thread,
mach_port_t task,
exception_type_t exception,
exception_data_t code,
mach_msg_type_number_t codeCnt,
int *flavor,
thread_state_t old_state,
mach_msg_type_number_t old_stateCnt,
thread_state_t new_state,
mach_msg_type_number_t *new_stateCnt
);
__END_DECLS
/********************** Caution **************************/
/* The following data types should be used to calculate */
/* maximum message sizes only. The actual message may be */
/* smaller, and the position of the arguments within the */
/* message layout may vary from what is presented here. */
/* For example, if any of the arguments are variable- */
/* sized, and less than the maximum is sent, the data */
/* will be packed tight in the actual message to reduce */
/* the presence of holes. */
/********************** Caution **************************/
/* typedefs for all requests */
#ifndef __Request__exc_subsystem__defined
#define __Request__exc_subsystem__defined
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t thread;
mach_msg_port_descriptor_t task;
/* end of the kernel processed data */
NDR_record_t NDR;
exception_type_t exception;
mach_msg_type_number_t codeCnt;
integer_t code[2];
} __Request__exception_raise_t;
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
exception_type_t exception;
mach_msg_type_number_t codeCnt;
integer_t code[2];
int flavor;
mach_msg_type_number_t old_stateCnt;
natural_t old_state[224];
} __Request__exception_raise_state_t;
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t thread;
mach_msg_port_descriptor_t task;
/* end of the kernel processed data */
NDR_record_t NDR;
exception_type_t exception;
mach_msg_type_number_t codeCnt;
integer_t code[2];
int flavor;
mach_msg_type_number_t old_stateCnt;
natural_t old_state[224];
} __Request__exception_raise_state_identity_t;
#ifdef __MigPackStructs
#pragma pack()
#endif
#endif /* !__Request__exc_subsystem__defined */
/* union of all requests */
#ifndef __RequestUnion__exc_subsystem__defined
#define __RequestUnion__exc_subsystem__defined
union __RequestUnion__exc_subsystem {
__Request__exception_raise_t Request_exception_raise;
__Request__exception_raise_state_t Request_exception_raise_state;
__Request__exception_raise_state_identity_t Request_exception_raise_state_identity;
};
#endif /* !__RequestUnion__exc_subsystem__defined */
/* typedefs for all replies */
#ifndef __Reply__exc_subsystem__defined
#define __Reply__exc_subsystem__defined
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
} __Reply__exception_raise_t;
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
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__exception_raise_state_t;
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
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__exception_raise_state_identity_t;
#ifdef __MigPackStructs
#pragma pack()
#endif
#endif /* !__Reply__exc_subsystem__defined */
/* union of all replies */
#ifndef __ReplyUnion__exc_subsystem__defined
#define __ReplyUnion__exc_subsystem__defined
union __ReplyUnion__exc_subsystem {
__Reply__exception_raise_t Reply_exception_raise;
__Reply__exception_raise_state_t Reply_exception_raise_state;
__Reply__exception_raise_state_identity_t Reply_exception_raise_state_identity;
};
#endif /* !__RequestUnion__exc_subsystem__defined */
#ifndef subsystem_to_name_map_exc
#define subsystem_to_name_map_exc \
{ "exception_raise", 2401 },\
{ "exception_raise_state", 2402 },\
{ "exception_raise_state_identity", 2403 }
#endif
#ifdef __AfterMigUserHeader
__AfterMigUserHeader
#endif /* __AfterMigUserHeader */
#endif /* _exc_user_ */

View File

@ -0,0 +1,770 @@
//+build darwin,macnative
/*
* IDENTIFICATION:
* stub generated Sun Feb 22 20:54:31 2015
* with a MiG generated by bootstrap_cmds-91
* OPTIONS:
*/
#define __MIG_check__Reply__exc_subsystem__ 1
#include "exc.h"
#ifndef mig_internal
#define mig_internal static __inline__
#endif /* mig_internal */
#ifndef mig_external
#define mig_external
#endif /* mig_external */
#if !defined(__MigTypeCheck) && defined(TypeCheck)
#define __MigTypeCheck TypeCheck /* Legacy setting */
#endif /* !defined(__MigTypeCheck) */
#if !defined(__MigKernelSpecificCode) && defined(_MIG_KERNEL_SPECIFIC_CODE_)
#define __MigKernelSpecificCode _MIG_KERNEL_SPECIFIC_CODE_ /* Legacy setting */
#endif /* !defined(__MigKernelSpecificCode) */
#ifndef LimitCheck
#define LimitCheck 0
#endif /* LimitCheck */
#ifndef min
#define min(a,b) ( ((a) < (b))? (a): (b) )
#endif /* min */
#if !defined(_WALIGN_)
#define _WALIGN_(x) (((x) + 3) & ~3)
#endif /* !defined(_WALIGN_) */
#if !defined(_WALIGNSZ_)
#define _WALIGNSZ_(x) _WALIGN_(sizeof(x))
#endif /* !defined(_WALIGNSZ_) */
#ifndef UseStaticTemplates
#define UseStaticTemplates 0
#endif /* UseStaticTemplates */
#ifndef __MachMsgErrorWithTimeout
#define __MachMsgErrorWithTimeout(_R_) { \
switch (_R_) { \
case MACH_SEND_INVALID_DATA: \
case MACH_SEND_INVALID_DEST: \
case MACH_SEND_INVALID_HEADER: \
mig_put_reply_port(InP->Head.msgh_reply_port); \
break; \
case MACH_SEND_TIMED_OUT: \
case MACH_RCV_TIMED_OUT: \
default: \
mig_dealloc_reply_port(InP->Head.msgh_reply_port); \
} \
}
#endif /* __MachMsgErrorWithTimeout */
#ifndef __MachMsgErrorWithoutTimeout
#define __MachMsgErrorWithoutTimeout(_R_) { \
switch (_R_) { \
case MACH_SEND_INVALID_DATA: \
case MACH_SEND_INVALID_DEST: \
case MACH_SEND_INVALID_HEADER: \
mig_put_reply_port(InP->Head.msgh_reply_port); \
break; \
default: \
mig_dealloc_reply_port(InP->Head.msgh_reply_port); \
} \
}
#endif /* __MachMsgErrorWithoutTimeout */
#ifndef __DeclareSendRpc
#define __DeclareSendRpc(_NUM_, _NAME_)
#endif /* __DeclareSendRpc */
#ifndef __BeforeSendRpc
#define __BeforeSendRpc(_NUM_, _NAME_)
#endif /* __BeforeSendRpc */
#ifndef __AfterSendRpc
#define __AfterSendRpc(_NUM_, _NAME_)
#endif /* __AfterSendRpc */
#ifndef __DeclareSendSimple
#define __DeclareSendSimple(_NUM_, _NAME_)
#endif /* __DeclareSendSimple */
#ifndef __BeforeSendSimple
#define __BeforeSendSimple(_NUM_, _NAME_)
#endif /* __BeforeSendSimple */
#ifndef __AfterSendSimple
#define __AfterSendSimple(_NUM_, _NAME_)
#endif /* __AfterSendSimple */
#define msgh_request_port msgh_remote_port
#define msgh_reply_port msgh_local_port
#if ( __MigTypeCheck )
#if __MIG_check__Reply__exc_subsystem__
#if !defined(__MIG_check__Reply__exception_raise_t__defined)
#define __MIG_check__Reply__exception_raise_t__defined
mig_internal kern_return_t __MIG_check__Reply__exception_raise_t(__Reply__exception_raise_t *Out0P)
{
typedef __Reply__exception_raise_t __Reply;
if (Out0P->Head.msgh_id != 2501) {
if (Out0P->Head.msgh_id == MACH_NOTIFY_SEND_ONCE)
{ return MIG_SERVER_DIED; }
else
{ return MIG_REPLY_MISMATCH; }
}
#if __MigTypeCheck
if ((Out0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||
(Out0P->Head.msgh_size != (mach_msg_size_t)sizeof(__Reply)))
{ return MIG_TYPE_ERROR ; }
#endif /* __MigTypeCheck */
{
return Out0P->RetCode;
}
}
#endif /* !defined(__MIG_check__Reply__exception_raise_t__defined) */
#endif /* __MIG_check__Reply__exc_subsystem__ */
#endif /* ( __MigTypeCheck ) */
/* Routine exception_raise */
mig_external kern_return_t exception_raise
(
mach_port_t exception_port,
mach_port_t thread,
mach_port_t task,
exception_type_t exception,
exception_data_t code,
mach_msg_type_number_t codeCnt
)
{
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t thread;
mach_msg_port_descriptor_t task;
/* end of the kernel processed data */
NDR_record_t NDR;
exception_type_t exception;
mach_msg_type_number_t codeCnt;
integer_t code[2];
} Request;
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
mach_msg_trailer_t trailer;
} Reply;
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
} __Reply;
#ifdef __MigPackStructs
#pragma pack()
#endif
/*
* typedef struct {
* mach_msg_header_t Head;
* NDR_record_t NDR;
* kern_return_t RetCode;
* } mig_reply_error_t;
*/
union {
Request In;
Reply Out;
} Mess;
Request *InP = &Mess.In;
Reply *Out0P = &Mess.Out;
mach_msg_return_t msg_result;
unsigned int msgh_size;
#ifdef __MIG_check__Reply__exception_raise_t__defined
kern_return_t check_result;
#endif /* __MIG_check__Reply__exception_raise_t__defined */
__DeclareSendRpc(2401, "exception_raise")
#if UseStaticTemplates
const static mach_msg_port_descriptor_t threadTemplate = {
/* name = */ MACH_PORT_NULL,
/* pad1 = */ 0,
/* pad2 = */ 0,
/* disp = */ 19,
/* type = */ MACH_MSG_PORT_DESCRIPTOR,
};
#endif /* UseStaticTemplates */
#if UseStaticTemplates
const static mach_msg_port_descriptor_t taskTemplate = {
/* name = */ MACH_PORT_NULL,
/* pad1 = */ 0,
/* pad2 = */ 0,
/* disp = */ 19,
/* type = */ MACH_MSG_PORT_DESCRIPTOR,
};
#endif /* UseStaticTemplates */
InP->msgh_body.msgh_descriptor_count = 2;
#if UseStaticTemplates
InP->thread = threadTemplate;
InP->thread.name = thread;
#else /* UseStaticTemplates */
InP->thread.name = thread;
InP->thread.disposition = 19;
InP->thread.type = MACH_MSG_PORT_DESCRIPTOR;
#endif /* UseStaticTemplates */
#if UseStaticTemplates
InP->task = taskTemplate;
InP->task.name = task;
#else /* UseStaticTemplates */
InP->task.name = task;
InP->task.disposition = 19;
InP->task.type = MACH_MSG_PORT_DESCRIPTOR;
#endif /* UseStaticTemplates */
InP->NDR = NDR_record;
InP->exception = exception;
if (codeCnt > 2) {
{ return MIG_ARRAY_TOO_LARGE; }
}
(void)memcpy((char *) InP->code, (const char *) code, 4 * codeCnt);
InP->codeCnt = codeCnt;
msgh_size = (mach_msg_size_t)(sizeof(Request) - 8) + ((4 * codeCnt));
InP->Head.msgh_bits = MACH_MSGH_BITS_COMPLEX|
MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);
/* msgh_size passed as argument */
InP->Head.msgh_request_port = exception_port;
InP->Head.msgh_reply_port = mig_get_reply_port();
InP->Head.msgh_id = 2401;
/* BEGIN VOUCHER CODE */
#ifdef USING_VOUCHERS
if (voucher_mach_msg_set != NULL) {
voucher_mach_msg_set(&InP->Head);
}
#endif // USING_VOUCHERS
/* END VOUCHER CODE */
__BeforeSendRpc(2401, "exception_raise")
msg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, msgh_size, (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
__AfterSendRpc(2401, "exception_raise")
if (msg_result != MACH_MSG_SUCCESS) {
__MachMsgErrorWithoutTimeout(msg_result);
{ return msg_result; }
}
#if defined(__MIG_check__Reply__exception_raise_t__defined)
check_result = __MIG_check__Reply__exception_raise_t((__Reply__exception_raise_t *)Out0P);
if (check_result != MACH_MSG_SUCCESS)
{ return check_result; }
#endif /* defined(__MIG_check__Reply__exception_raise_t__defined) */
return KERN_SUCCESS;
}
#if ( __MigTypeCheck )
#if __MIG_check__Reply__exc_subsystem__
#if !defined(__MIG_check__Reply__exception_raise_state_t__defined)
#define __MIG_check__Reply__exception_raise_state_t__defined
mig_internal kern_return_t __MIG_check__Reply__exception_raise_state_t(__Reply__exception_raise_state_t *Out0P)
{
typedef __Reply__exception_raise_state_t __Reply;
#if __MigTypeCheck
unsigned int msgh_size;
#endif /* __MigTypeCheck */
if (Out0P->Head.msgh_id != 2502) {
if (Out0P->Head.msgh_id == MACH_NOTIFY_SEND_ONCE)
{ return MIG_SERVER_DIED; }
else
{ return MIG_REPLY_MISMATCH; }
}
#if __MigTypeCheck
msgh_size = Out0P->Head.msgh_size;
if ((Out0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||
((msgh_size > (mach_msg_size_t)sizeof(__Reply) || msgh_size < (mach_msg_size_t)(sizeof(__Reply) - 896)) &&
(msgh_size != (mach_msg_size_t)sizeof(mig_reply_error_t) ||
Out0P->RetCode == KERN_SUCCESS)))
{ return MIG_TYPE_ERROR ; }
#endif /* __MigTypeCheck */
if (Out0P->RetCode != KERN_SUCCESS) {
return ((mig_reply_error_t *)Out0P)->RetCode;
}
#if __MigTypeCheck
if ( Out0P->new_stateCnt > 224 )
return MIG_TYPE_ERROR;
if (((msgh_size - (mach_msg_size_t)(sizeof(__Reply) - 896)) / 4< Out0P->new_stateCnt) ||
(msgh_size != (mach_msg_size_t)(sizeof(__Reply) - 896) + Out0P->new_stateCnt * 4))
{ return MIG_TYPE_ERROR ; }
#endif /* __MigTypeCheck */
return MACH_MSG_SUCCESS;
}
#endif /* !defined(__MIG_check__Reply__exception_raise_state_t__defined) */
#endif /* __MIG_check__Reply__exc_subsystem__ */
#endif /* ( __MigTypeCheck ) */
/* Routine exception_raise_state */
mig_external kern_return_t exception_raise_state
(
mach_port_t exception_port,
exception_type_t exception,
const exception_data_t code,
mach_msg_type_number_t codeCnt,
int *flavor,
const thread_state_t old_state,
mach_msg_type_number_t old_stateCnt,
thread_state_t new_state,
mach_msg_type_number_t *new_stateCnt
)
{
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
exception_type_t exception;
mach_msg_type_number_t codeCnt;
integer_t code[2];
int flavor;
mach_msg_type_number_t old_stateCnt;
natural_t old_state[224];
} Request;
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
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];
mach_msg_trailer_t trailer;
} Reply;
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
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;
#ifdef __MigPackStructs
#pragma pack()
#endif
/*
* typedef struct {
* mach_msg_header_t Head;
* NDR_record_t NDR;
* kern_return_t RetCode;
* } mig_reply_error_t;
*/
union {
Request In;
Reply Out;
} Mess;
Request *InP = &Mess.In;
Reply *Out0P = &Mess.Out;
mach_msg_return_t msg_result;
unsigned int msgh_size;
unsigned int msgh_size_delta;
#ifdef __MIG_check__Reply__exception_raise_state_t__defined
kern_return_t check_result;
#endif /* __MIG_check__Reply__exception_raise_state_t__defined */
__DeclareSendRpc(2402, "exception_raise_state")
InP->NDR = NDR_record;
InP->exception = exception;
if (codeCnt > 2) {
{ return MIG_ARRAY_TOO_LARGE; }
}
(void)memcpy((char *) InP->code, (const char *) code, 4 * codeCnt);
InP->codeCnt = codeCnt;
msgh_size_delta = (4 * codeCnt);
msgh_size = (mach_msg_size_t)(sizeof(Request) - 904) + msgh_size_delta;
InP = (Request *) ((pointer_t) InP + msgh_size_delta - 8);
InP->flavor = *flavor;
if (old_stateCnt > 224) {
{ return MIG_ARRAY_TOO_LARGE; }
}
(void)memcpy((char *) InP->old_state, (const char *) old_state, 4 * old_stateCnt);
InP->old_stateCnt = old_stateCnt;
msgh_size += (4 * old_stateCnt);
InP = &Mess.In;
InP->Head.msgh_bits =
MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);
/* msgh_size passed as argument */
InP->Head.msgh_request_port = exception_port;
InP->Head.msgh_reply_port = mig_get_reply_port();
InP->Head.msgh_id = 2402;
/* BEGIN VOUCHER CODE */
#ifdef USING_VOUCHERS
if (voucher_mach_msg_set != NULL) {
voucher_mach_msg_set(&InP->Head);
}
#endif // USING_VOUCHERS
/* END VOUCHER CODE */
__BeforeSendRpc(2402, "exception_raise_state")
msg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, msgh_size, (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
__AfterSendRpc(2402, "exception_raise_state")
if (msg_result != MACH_MSG_SUCCESS) {
__MachMsgErrorWithoutTimeout(msg_result);
{ return msg_result; }
}
#if defined(__MIG_check__Reply__exception_raise_state_t__defined)
check_result = __MIG_check__Reply__exception_raise_state_t((__Reply__exception_raise_state_t *)Out0P);
if (check_result != MACH_MSG_SUCCESS)
{ return check_result; }
#endif /* defined(__MIG_check__Reply__exception_raise_state_t__defined) */
*flavor = Out0P->flavor;
if (Out0P->new_stateCnt > 224) {
(void)memcpy((char *) new_state, (const char *) Out0P->new_state, 4 * 224);
*new_stateCnt = Out0P->new_stateCnt;
{ return MIG_ARRAY_TOO_LARGE; }
}
(void)memcpy((char *) new_state, (const char *) Out0P->new_state, 4 * Out0P->new_stateCnt);
*new_stateCnt = Out0P->new_stateCnt;
return KERN_SUCCESS;
}
#if ( __MigTypeCheck )
#if __MIG_check__Reply__exc_subsystem__
#if !defined(__MIG_check__Reply__exception_raise_state_identity_t__defined)
#define __MIG_check__Reply__exception_raise_state_identity_t__defined
mig_internal kern_return_t __MIG_check__Reply__exception_raise_state_identity_t(__Reply__exception_raise_state_identity_t *Out0P)
{
typedef __Reply__exception_raise_state_identity_t __Reply;
#if __MigTypeCheck
unsigned int msgh_size;
#endif /* __MigTypeCheck */
if (Out0P->Head.msgh_id != 2503) {
if (Out0P->Head.msgh_id == MACH_NOTIFY_SEND_ONCE)
{ return MIG_SERVER_DIED; }
else
{ return MIG_REPLY_MISMATCH; }
}
#if __MigTypeCheck
msgh_size = Out0P->Head.msgh_size;
if ((Out0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||
((msgh_size > (mach_msg_size_t)sizeof(__Reply) || msgh_size < (mach_msg_size_t)(sizeof(__Reply) - 896)) &&
(msgh_size != (mach_msg_size_t)sizeof(mig_reply_error_t) ||
Out0P->RetCode == KERN_SUCCESS)))
{ return MIG_TYPE_ERROR ; }
#endif /* __MigTypeCheck */
if (Out0P->RetCode != KERN_SUCCESS) {
return ((mig_reply_error_t *)Out0P)->RetCode;
}
#if __MigTypeCheck
if ( Out0P->new_stateCnt > 224 )
return MIG_TYPE_ERROR;
if (((msgh_size - (mach_msg_size_t)(sizeof(__Reply) - 896)) / 4< Out0P->new_stateCnt) ||
(msgh_size != (mach_msg_size_t)(sizeof(__Reply) - 896) + Out0P->new_stateCnt * 4))
{ return MIG_TYPE_ERROR ; }
#endif /* __MigTypeCheck */
return MACH_MSG_SUCCESS;
}
#endif /* !defined(__MIG_check__Reply__exception_raise_state_identity_t__defined) */
#endif /* __MIG_check__Reply__exc_subsystem__ */
#endif /* ( __MigTypeCheck ) */
/* Routine exception_raise_state_identity */
mig_external kern_return_t exception_raise_state_identity
(
mach_port_t exception_port,
mach_port_t thread,
mach_port_t task,
exception_type_t exception,
exception_data_t code,
mach_msg_type_number_t codeCnt,
int *flavor,
thread_state_t old_state,
mach_msg_type_number_t old_stateCnt,
thread_state_t new_state,
mach_msg_type_number_t *new_stateCnt
)
{
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t thread;
mach_msg_port_descriptor_t task;
/* end of the kernel processed data */
NDR_record_t NDR;
exception_type_t exception;
mach_msg_type_number_t codeCnt;
integer_t code[2];
int flavor;
mach_msg_type_number_t old_stateCnt;
natural_t old_state[224];
} Request;
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
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];
mach_msg_trailer_t trailer;
} Reply;
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
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;
#ifdef __MigPackStructs
#pragma pack()
#endif
/*
* typedef struct {
* mach_msg_header_t Head;
* NDR_record_t NDR;
* kern_return_t RetCode;
* } mig_reply_error_t;
*/
union {
Request In;
Reply Out;
} Mess;
Request *InP = &Mess.In;
Reply *Out0P = &Mess.Out;
mach_msg_return_t msg_result;
unsigned int msgh_size;
unsigned int msgh_size_delta;
#ifdef __MIG_check__Reply__exception_raise_state_identity_t__defined
kern_return_t check_result;
#endif /* __MIG_check__Reply__exception_raise_state_identity_t__defined */
__DeclareSendRpc(2403, "exception_raise_state_identity")
#if UseStaticTemplates
const static mach_msg_port_descriptor_t threadTemplate = {
/* name = */ MACH_PORT_NULL,
/* pad1 = */ 0,
/* pad2 = */ 0,
/* disp = */ 19,
/* type = */ MACH_MSG_PORT_DESCRIPTOR,
};
#endif /* UseStaticTemplates */
#if UseStaticTemplates
const static mach_msg_port_descriptor_t taskTemplate = {
/* name = */ MACH_PORT_NULL,
/* pad1 = */ 0,
/* pad2 = */ 0,
/* disp = */ 19,
/* type = */ MACH_MSG_PORT_DESCRIPTOR,
};
#endif /* UseStaticTemplates */
InP->msgh_body.msgh_descriptor_count = 2;
#if UseStaticTemplates
InP->thread = threadTemplate;
InP->thread.name = thread;
#else /* UseStaticTemplates */
InP->thread.name = thread;
InP->thread.disposition = 19;
InP->thread.type = MACH_MSG_PORT_DESCRIPTOR;
#endif /* UseStaticTemplates */
#if UseStaticTemplates
InP->task = taskTemplate;
InP->task.name = task;
#else /* UseStaticTemplates */
InP->task.name = task;
InP->task.disposition = 19;
InP->task.type = MACH_MSG_PORT_DESCRIPTOR;
#endif /* UseStaticTemplates */
InP->NDR = NDR_record;
InP->exception = exception;
if (codeCnt > 2) {
{ return MIG_ARRAY_TOO_LARGE; }
}
(void)memcpy((char *) InP->code, (const char *) code, 4 * codeCnt);
InP->codeCnt = codeCnt;
msgh_size_delta = (4 * codeCnt);
msgh_size = (mach_msg_size_t)(sizeof(Request) - 904) + msgh_size_delta;
InP = (Request *) ((pointer_t) InP + msgh_size_delta - 8);
InP->flavor = *flavor;
if (old_stateCnt > 224) {
{ return MIG_ARRAY_TOO_LARGE; }
}
(void)memcpy((char *) InP->old_state, (const char *) old_state, 4 * old_stateCnt);
InP->old_stateCnt = old_stateCnt;
msgh_size += (4 * old_stateCnt);
InP = &Mess.In;
InP->Head.msgh_bits = MACH_MSGH_BITS_COMPLEX|
MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);
/* msgh_size passed as argument */
InP->Head.msgh_request_port = exception_port;
InP->Head.msgh_reply_port = mig_get_reply_port();
InP->Head.msgh_id = 2403;
/* BEGIN VOUCHER CODE */
#ifdef USING_VOUCHERS
if (voucher_mach_msg_set != NULL) {
voucher_mach_msg_set(&InP->Head);
}
#endif // USING_VOUCHERS
/* END VOUCHER CODE */
__BeforeSendRpc(2403, "exception_raise_state_identity")
msg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, msgh_size, (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
__AfterSendRpc(2403, "exception_raise_state_identity")
if (msg_result != MACH_MSG_SUCCESS) {
__MachMsgErrorWithoutTimeout(msg_result);
{ return msg_result; }
}
#if defined(__MIG_check__Reply__exception_raise_state_identity_t__defined)
check_result = __MIG_check__Reply__exception_raise_state_identity_t((__Reply__exception_raise_state_identity_t *)Out0P);
if (check_result != MACH_MSG_SUCCESS)
{ return check_result; }
#endif /* defined(__MIG_check__Reply__exception_raise_state_identity_t__defined) */
*flavor = Out0P->flavor;
if (Out0P->new_stateCnt > 224) {
(void)memcpy((char *) new_state, (const char *) Out0P->new_state, 4 * 224);
*new_stateCnt = Out0P->new_stateCnt;
{ return MIG_ARRAY_TOO_LARGE; }
}
(void)memcpy((char *) new_state, (const char *) Out0P->new_state, 4 * Out0P->new_stateCnt);
*new_stateCnt = Out0P->new_stateCnt;
return KERN_SUCCESS;
}

View File

@ -0,0 +1,114 @@
//+build darwin,macnative
#include "exec_darwin.h"
#include "stdio.h"
extern char** environ;
int
close_exec_pipe(int fd[2]) {
if (pipe(fd) < 0) return -1;
if (fcntl(fd[0], F_SETFD, FD_CLOEXEC) < 0) return -1;
if (fcntl(fd[1], F_SETFD, FD_CLOEXEC) < 0) return -1;
return 0;
}
int
fork_exec(char *argv0, char **argv, int size,
char *wd,
task_t *task,
mach_port_t *port_set,
mach_port_t *exception_port,
mach_port_t *notification_port)
{
// Since we're using mach exceptions instead of signals,
// we need to coordinate between parent and child via pipes
// to ensure that the parent has set the exception ports on
// the child task before it execs.
int fd[2];
if (close_exec_pipe(fd) < 0) return -1;
// Create another pipe to signal the parent on exec.
int efd[2];
if (close_exec_pipe(efd) < 0) return -1;
kern_return_t kret;
pid_t pid = fork();
if (pid > 0) {
// In parent.
close(fd[0]);
close(efd[1]);
kret = acquire_mach_task(pid, task, port_set, exception_port, notification_port);
if (kret != KERN_SUCCESS) return -1;
char msg = 'c';
write(fd[1], &msg, 1);
close(fd[1]);
char w;
size_t n = read(efd[0], &w, 1);
close(efd[0]);
if (n != 0) {
// Child died, reap it.
waitpid(pid, NULL, 0);
return -1;
}
return pid;
}
// Fork succeeded, we are in the child.
int pret, cret;
char sig;
close(fd[1]);
read(fd[0], &sig, 1);
close(fd[0]);
// Create a new process group.
if (setpgid(0, 0) < 0) {
perror("setpgid");
exit(1);
}
// Set errno to zero before a call to ptrace.
// It is documented that ptrace can return -1 even
// for successful calls.
errno = 0;
pret = ptrace(PT_TRACE_ME, 0, 0, 0);
if (pret != 0 && errno != 0) {
perror("ptrace");
exit(1);
}
// Change working directory if wd is not empty.
if (wd && wd[0]) {
errno = 0;
cret = chdir(wd);
if (cret != 0 && errno != 0) {
char *error_msg;
asprintf(&error_msg, "%s '%s'", "chdir", wd);
perror(error_msg);
exit(1);
}
}
errno = 0;
pret = ptrace(PT_SIGEXC, 0, 0, 0);
if (pret != 0 && errno != 0) {
perror("ptrace");
exit(1);
}
sleep(1);
// Create the child process.
execve(argv0, argv, environ);
// We should never reach here, but if we did something went wrong.
// Write a message to parent to alert that exec failed.
char msg = 'd';
write(efd[1], &msg, 1);
close(efd[1]);
exit(1);
}

View File

@ -0,0 +1,12 @@
//+build darwin,macnative
#include "proc_darwin.h"
#include <unistd.h>
#include <sys/ptrace.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
int
fork_exec(char *, char **, int, char *, task_t*, mach_port_t*, mach_port_t*, mach_port_t*);

View File

@ -0,0 +1,283 @@
#ifndef _mach_exc_user_
#define _mach_exc_user_
/* Module mach_exc */
#include <string.h>
#include <mach/ndr.h>
#include <mach/boolean.h>
#include <mach/kern_return.h>
#include <mach/notify.h>
#include <mach/mach_types.h>
#include <mach/message.h>
#include <mach/mig_errors.h>
#include <mach/port.h>
/* BEGIN VOUCHER CODE */
#ifndef KERNEL
#if defined(__has_include)
#if __has_include(<mach/mig_voucher_support.h>)
#ifndef USING_VOUCHERS
#define USING_VOUCHERS
#endif
#ifndef __VOUCHER_FORWARD_TYPE_DECLS__
#define __VOUCHER_FORWARD_TYPE_DECLS__
#ifdef __cplusplus
extern "C" {
#endif
extern boolean_t voucher_mach_msg_set(mach_msg_header_t *msg) __attribute__((weak_import));
#ifdef __cplusplus
}
#endif
#endif // __VOUCHER_FORWARD_TYPE_DECLS__
#endif // __has_include(<mach/mach_voucher_types.h>)
#endif // __has_include
#endif // !KERNEL
/* END VOUCHER CODE */
#ifdef AUTOTEST
#ifndef FUNCTION_PTR_T
#define FUNCTION_PTR_T
typedef void (*function_ptr_t)(mach_port_t, char *, mach_msg_type_number_t);
typedef struct {
char *name;
function_ptr_t function;
} function_table_entry;
typedef function_table_entry *function_table_t;
#endif /* FUNCTION_PTR_T */
#endif /* AUTOTEST */
#ifndef mach_exc_MSG_COUNT
#define mach_exc_MSG_COUNT 3
#endif /* mach_exc_MSG_COUNT */
#include <mach/std_types.h>
#include <mach/mig.h>
#include <mach/mig.h>
#include <mach/mach_types.h>
#ifdef __BeforeMigUserHeader
__BeforeMigUserHeader
#endif /* __BeforeMigUserHeader */
#include <sys/cdefs.h>
__BEGIN_DECLS
/* Routine mach_exception_raise */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t mach_exception_raise
(
mach_port_t exception_port,
mach_port_t thread,
mach_port_t task,
exception_type_t exception,
mach_exception_data_t code,
mach_msg_type_number_t codeCnt
);
/* Routine mach_exception_raise_state */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t mach_exception_raise_state
(
mach_port_t exception_port,
exception_type_t exception,
const mach_exception_data_t code,
mach_msg_type_number_t codeCnt,
int *flavor,
const thread_state_t old_state,
mach_msg_type_number_t old_stateCnt,
thread_state_t new_state,
mach_msg_type_number_t *new_stateCnt
);
/* Routine mach_exception_raise_state_identity */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t mach_exception_raise_state_identity
(
mach_port_t exception_port,
mach_port_t thread,
mach_port_t task,
exception_type_t exception,
mach_exception_data_t code,
mach_msg_type_number_t codeCnt,
int *flavor,
thread_state_t old_state,
mach_msg_type_number_t old_stateCnt,
thread_state_t new_state,
mach_msg_type_number_t *new_stateCnt
);
__END_DECLS
/********************** Caution **************************/
/* The following data types should be used to calculate */
/* maximum message sizes only. The actual message may be */
/* smaller, and the position of the arguments within the */
/* message layout may vary from what is presented here. */
/* For example, if any of the arguments are variable- */
/* sized, and less than the maximum is sent, the data */
/* will be packed tight in the actual message to reduce */
/* the presence of holes. */
/********************** Caution **************************/
/* typedefs for all requests */
#ifndef __Request__mach_exc_subsystem__defined
#define __Request__mach_exc_subsystem__defined
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t thread;
mach_msg_port_descriptor_t task;
/* end of the kernel processed data */
NDR_record_t NDR;
exception_type_t exception;
mach_msg_type_number_t codeCnt;
int64_t code[2];
} __Request__mach_exception_raise_t;
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
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;
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t thread;
mach_msg_port_descriptor_t task;
/* end of the kernel processed data */
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_identity_t;
#ifdef __MigPackStructs
#pragma pack()
#endif
#endif /* !__Request__mach_exc_subsystem__defined */
/* union of all requests */
#ifndef __RequestUnion__mach_exc_subsystem__defined
#define __RequestUnion__mach_exc_subsystem__defined
union __RequestUnion__mach_exc_subsystem {
__Request__mach_exception_raise_t Request_mach_exception_raise;
__Request__mach_exception_raise_state_t Request_mach_exception_raise_state;
__Request__mach_exception_raise_state_identity_t Request_mach_exception_raise_state_identity;
};
#endif /* !__RequestUnion__mach_exc_subsystem__defined */
/* typedefs for all replies */
#ifndef __Reply__mach_exc_subsystem__defined
#define __Reply__mach_exc_subsystem__defined
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
} __Reply__mach_exception_raise_t;
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
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_t;
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
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;
#ifdef __MigPackStructs
#pragma pack()
#endif
#endif /* !__Reply__mach_exc_subsystem__defined */
/* union of all replies */
#ifndef __ReplyUnion__mach_exc_subsystem__defined
#define __ReplyUnion__mach_exc_subsystem__defined
union __ReplyUnion__mach_exc_subsystem {
__Reply__mach_exception_raise_t Reply_mach_exception_raise;
__Reply__mach_exception_raise_state_t Reply_mach_exception_raise_state;
__Reply__mach_exception_raise_state_identity_t Reply_mach_exception_raise_state_identity;
};
#endif /* !__RequestUnion__mach_exc_subsystem__defined */
#ifndef subsystem_to_name_map_mach_exc
#define subsystem_to_name_map_mach_exc \
{ "mach_exception_raise", 2401 },\
{ "mach_exception_raise_state", 2402 },\
{ "mach_exception_raise_state_identity", 2403 }
#endif
#ifdef __AfterMigUserHeader
__AfterMigUserHeader
#endif /* __AfterMigUserHeader */
#endif /* _mach_exc_user_ */

View File

@ -0,0 +1,770 @@
//+build darwin,macnative
/*
* IDENTIFICATION:
* stub generated Sat Feb 21 18:10:52 2015
* with a MiG generated by bootstrap_cmds-91
* OPTIONS:
*/
#define __MIG_check__Reply__mach_exc_subsystem__ 1
#include "mach_exc.h"
#ifndef mig_internal
#define mig_internal static __inline__
#endif /* mig_internal */
#ifndef mig_external
#define mig_external
#endif /* mig_external */
#if !defined(__MigTypeCheck) && defined(TypeCheck)
#define __MigTypeCheck TypeCheck /* Legacy setting */
#endif /* !defined(__MigTypeCheck) */
#if !defined(__MigKernelSpecificCode) && defined(_MIG_KERNEL_SPECIFIC_CODE_)
#define __MigKernelSpecificCode _MIG_KERNEL_SPECIFIC_CODE_ /* Legacy setting */
#endif /* !defined(__MigKernelSpecificCode) */
#ifndef LimitCheck
#define LimitCheck 0
#endif /* LimitCheck */
#ifndef min
#define min(a,b) ( ((a) < (b))? (a): (b) )
#endif /* min */
#if !defined(_WALIGN_)
#define _WALIGN_(x) (((x) + 3) & ~3)
#endif /* !defined(_WALIGN_) */
#if !defined(_WALIGNSZ_)
#define _WALIGNSZ_(x) _WALIGN_(sizeof(x))
#endif /* !defined(_WALIGNSZ_) */
#ifndef UseStaticTemplates
#define UseStaticTemplates 0
#endif /* UseStaticTemplates */
#ifndef __MachMsgErrorWithTimeout
#define __MachMsgErrorWithTimeout(_R_) { \
switch (_R_) { \
case MACH_SEND_INVALID_DATA: \
case MACH_SEND_INVALID_DEST: \
case MACH_SEND_INVALID_HEADER: \
mig_put_reply_port(InP->Head.msgh_reply_port); \
break; \
case MACH_SEND_TIMED_OUT: \
case MACH_RCV_TIMED_OUT: \
default: \
mig_dealloc_reply_port(InP->Head.msgh_reply_port); \
} \
}
#endif /* __MachMsgErrorWithTimeout */
#ifndef __MachMsgErrorWithoutTimeout
#define __MachMsgErrorWithoutTimeout(_R_) { \
switch (_R_) { \
case MACH_SEND_INVALID_DATA: \
case MACH_SEND_INVALID_DEST: \
case MACH_SEND_INVALID_HEADER: \
mig_put_reply_port(InP->Head.msgh_reply_port); \
break; \
default: \
mig_dealloc_reply_port(InP->Head.msgh_reply_port); \
} \
}
#endif /* __MachMsgErrorWithoutTimeout */
#ifndef __DeclareSendRpc
#define __DeclareSendRpc(_NUM_, _NAME_)
#endif /* __DeclareSendRpc */
#ifndef __BeforeSendRpc
#define __BeforeSendRpc(_NUM_, _NAME_)
#endif /* __BeforeSendRpc */
#ifndef __AfterSendRpc
#define __AfterSendRpc(_NUM_, _NAME_)
#endif /* __AfterSendRpc */
#ifndef __DeclareSendSimple
#define __DeclareSendSimple(_NUM_, _NAME_)
#endif /* __DeclareSendSimple */
#ifndef __BeforeSendSimple
#define __BeforeSendSimple(_NUM_, _NAME_)
#endif /* __BeforeSendSimple */
#ifndef __AfterSendSimple
#define __AfterSendSimple(_NUM_, _NAME_)
#endif /* __AfterSendSimple */
#define msgh_request_port msgh_remote_port
#define msgh_reply_port msgh_local_port
#if ( __MigTypeCheck )
#if __MIG_check__Reply__mach_exc_subsystem__
#if !defined(__MIG_check__Reply__mach_exception_raise_t__defined)
#define __MIG_check__Reply__mach_exception_raise_t__defined
mig_internal kern_return_t __MIG_check__Reply__mach_exception_raise_t(__Reply__mach_exception_raise_t *Out0P)
{
typedef __Reply__mach_exception_raise_t __Reply;
if (Out0P->Head.msgh_id != 2505) {
if (Out0P->Head.msgh_id == MACH_NOTIFY_SEND_ONCE)
{ return MIG_SERVER_DIED; }
else
{ return MIG_REPLY_MISMATCH; }
}
#if __MigTypeCheck
if ((Out0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||
(Out0P->Head.msgh_size != (mach_msg_size_t)sizeof(__Reply)))
{ return MIG_TYPE_ERROR ; }
#endif /* __MigTypeCheck */
{
return Out0P->RetCode;
}
}
#endif /* !defined(__MIG_check__Reply__mach_exception_raise_t__defined) */
#endif /* __MIG_check__Reply__mach_exc_subsystem__ */
#endif /* ( __MigTypeCheck ) */
/* Routine mach_exception_raise */
mig_external kern_return_t mach_exception_raise
(
mach_port_t exception_port,
mach_port_t thread,
mach_port_t task,
exception_type_t exception,
mach_exception_data_t code,
mach_msg_type_number_t codeCnt
)
{
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t thread;
mach_msg_port_descriptor_t task;
/* end of the kernel processed data */
NDR_record_t NDR;
exception_type_t exception;
mach_msg_type_number_t codeCnt;
int64_t code[2];
} Request;
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
mach_msg_trailer_t trailer;
} Reply;
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
} __Reply;
#ifdef __MigPackStructs
#pragma pack()
#endif
/*
* typedef struct {
* mach_msg_header_t Head;
* NDR_record_t NDR;
* kern_return_t RetCode;
* } mig_reply_error_t;
*/
union {
Request In;
Reply Out;
} Mess;
Request *InP = &Mess.In;
Reply *Out0P = &Mess.Out;
mach_msg_return_t msg_result;
unsigned int msgh_size;
#ifdef __MIG_check__Reply__mach_exception_raise_t__defined
kern_return_t check_result;
#endif /* __MIG_check__Reply__mach_exception_raise_t__defined */
__DeclareSendRpc(2405, "mach_exception_raise")
#if UseStaticTemplates
const static mach_msg_port_descriptor_t threadTemplate = {
/* name = */ MACH_PORT_NULL,
/* pad1 = */ 0,
/* pad2 = */ 0,
/* disp = */ 19,
/* type = */ MACH_MSG_PORT_DESCRIPTOR,
};
#endif /* UseStaticTemplates */
#if UseStaticTemplates
const static mach_msg_port_descriptor_t taskTemplate = {
/* name = */ MACH_PORT_NULL,
/* pad1 = */ 0,
/* pad2 = */ 0,
/* disp = */ 19,
/* type = */ MACH_MSG_PORT_DESCRIPTOR,
};
#endif /* UseStaticTemplates */
InP->msgh_body.msgh_descriptor_count = 2;
#if UseStaticTemplates
InP->thread = threadTemplate;
InP->thread.name = thread;
#else /* UseStaticTemplates */
InP->thread.name = thread;
InP->thread.disposition = 19;
InP->thread.type = MACH_MSG_PORT_DESCRIPTOR;
#endif /* UseStaticTemplates */
#if UseStaticTemplates
InP->task = taskTemplate;
InP->task.name = task;
#else /* UseStaticTemplates */
InP->task.name = task;
InP->task.disposition = 19;
InP->task.type = MACH_MSG_PORT_DESCRIPTOR;
#endif /* UseStaticTemplates */
InP->NDR = NDR_record;
InP->exception = exception;
if (codeCnt > 2) {
{ return MIG_ARRAY_TOO_LARGE; }
}
(void)memcpy((char *) InP->code, (const char *) code, 8 * codeCnt);
InP->codeCnt = codeCnt;
msgh_size = (mach_msg_size_t)(sizeof(Request) - 16) + ((8 * codeCnt));
InP->Head.msgh_bits = MACH_MSGH_BITS_COMPLEX|
MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);
/* msgh_size passed as argument */
InP->Head.msgh_request_port = exception_port;
InP->Head.msgh_reply_port = mig_get_reply_port();
InP->Head.msgh_id = 2405;
/* BEGIN VOUCHER CODE */
#ifdef USING_VOUCHERS
if (voucher_mach_msg_set != NULL) {
voucher_mach_msg_set(&InP->Head);
}
#endif // USING_VOUCHERS
/* END VOUCHER CODE */
__BeforeSendRpc(2405, "mach_exception_raise")
msg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, msgh_size, (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
__AfterSendRpc(2405, "mach_exception_raise")
if (msg_result != MACH_MSG_SUCCESS) {
__MachMsgErrorWithoutTimeout(msg_result);
{ return msg_result; }
}
#if defined(__MIG_check__Reply__mach_exception_raise_t__defined)
check_result = __MIG_check__Reply__mach_exception_raise_t((__Reply__mach_exception_raise_t *)Out0P);
if (check_result != MACH_MSG_SUCCESS)
{ return check_result; }
#endif /* defined(__MIG_check__Reply__mach_exception_raise_t__defined) */
return KERN_SUCCESS;
}
#if ( __MigTypeCheck )
#if __MIG_check__Reply__mach_exc_subsystem__
#if !defined(__MIG_check__Reply__mach_exception_raise_state_t__defined)
#define __MIG_check__Reply__mach_exception_raise_state_t__defined
mig_internal kern_return_t __MIG_check__Reply__mach_exception_raise_state_t(__Reply__mach_exception_raise_state_t *Out0P)
{
typedef __Reply__mach_exception_raise_state_t __Reply;
#if __MigTypeCheck
unsigned int msgh_size;
#endif /* __MigTypeCheck */
if (Out0P->Head.msgh_id != 2506) {
if (Out0P->Head.msgh_id == MACH_NOTIFY_SEND_ONCE)
{ return MIG_SERVER_DIED; }
else
{ return MIG_REPLY_MISMATCH; }
}
#if __MigTypeCheck
msgh_size = Out0P->Head.msgh_size;
if ((Out0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||
((msgh_size > (mach_msg_size_t)sizeof(__Reply) || msgh_size < (mach_msg_size_t)(sizeof(__Reply) - 896)) &&
(msgh_size != (mach_msg_size_t)sizeof(mig_reply_error_t) ||
Out0P->RetCode == KERN_SUCCESS)))
{ return MIG_TYPE_ERROR ; }
#endif /* __MigTypeCheck */
if (Out0P->RetCode != KERN_SUCCESS) {
return ((mig_reply_error_t *)Out0P)->RetCode;
}
#if __MigTypeCheck
if ( Out0P->new_stateCnt > 224 )
return MIG_TYPE_ERROR;
if (((msgh_size - (mach_msg_size_t)(sizeof(__Reply) - 896)) / 4< Out0P->new_stateCnt) ||
(msgh_size != (mach_msg_size_t)(sizeof(__Reply) - 896) + Out0P->new_stateCnt * 4))
{ return MIG_TYPE_ERROR ; }
#endif /* __MigTypeCheck */
return MACH_MSG_SUCCESS;
}
#endif /* !defined(__MIG_check__Reply__mach_exception_raise_state_t__defined) */
#endif /* __MIG_check__Reply__mach_exc_subsystem__ */
#endif /* ( __MigTypeCheck ) */
/* Routine mach_exception_raise_state */
mig_external kern_return_t mach_exception_raise_state
(
mach_port_t exception_port,
exception_type_t exception,
const mach_exception_data_t code,
mach_msg_type_number_t codeCnt,
int *flavor,
const thread_state_t old_state,
mach_msg_type_number_t old_stateCnt,
thread_state_t new_state,
mach_msg_type_number_t *new_stateCnt
)
{
#ifdef __MigPackStructs
#pragma pack(4)
#endif
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;
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
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];
mach_msg_trailer_t trailer;
} Reply;
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
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;
#ifdef __MigPackStructs
#pragma pack()
#endif
/*
* typedef struct {
* mach_msg_header_t Head;
* NDR_record_t NDR;
* kern_return_t RetCode;
* } mig_reply_error_t;
*/
union {
Request In;
Reply Out;
} Mess;
Request *InP = &Mess.In;
Reply *Out0P = &Mess.Out;
mach_msg_return_t msg_result;
unsigned int msgh_size;
unsigned int msgh_size_delta;
#ifdef __MIG_check__Reply__mach_exception_raise_state_t__defined
kern_return_t check_result;
#endif /* __MIG_check__Reply__mach_exception_raise_state_t__defined */
__DeclareSendRpc(2406, "mach_exception_raise_state")
InP->NDR = NDR_record;
InP->exception = exception;
if (codeCnt > 2) {
{ return MIG_ARRAY_TOO_LARGE; }
}
(void)memcpy((char *) InP->code, (const char *) code, 8 * codeCnt);
InP->codeCnt = codeCnt;
msgh_size_delta = (8 * codeCnt);
msgh_size = (mach_msg_size_t)(sizeof(Request) - 912) + msgh_size_delta;
InP = (Request *) ((pointer_t) InP + msgh_size_delta - 16);
InP->flavor = *flavor;
if (old_stateCnt > 224) {
{ return MIG_ARRAY_TOO_LARGE; }
}
(void)memcpy((char *) InP->old_state, (const char *) old_state, 4 * old_stateCnt);
InP->old_stateCnt = old_stateCnt;
msgh_size += (4 * old_stateCnt);
InP = &Mess.In;
InP->Head.msgh_bits =
MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);
/* msgh_size passed as argument */
InP->Head.msgh_request_port = exception_port;
InP->Head.msgh_reply_port = mig_get_reply_port();
InP->Head.msgh_id = 2406;
/* BEGIN VOUCHER CODE */
#ifdef USING_VOUCHERS
if (voucher_mach_msg_set != NULL) {
voucher_mach_msg_set(&InP->Head);
}
#endif // USING_VOUCHERS
/* END VOUCHER CODE */
__BeforeSendRpc(2406, "mach_exception_raise_state")
msg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, msgh_size, (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
__AfterSendRpc(2406, "mach_exception_raise_state")
if (msg_result != MACH_MSG_SUCCESS) {
__MachMsgErrorWithoutTimeout(msg_result);
{ return msg_result; }
}
#if defined(__MIG_check__Reply__mach_exception_raise_state_t__defined)
check_result = __MIG_check__Reply__mach_exception_raise_state_t((__Reply__mach_exception_raise_state_t *)Out0P);
if (check_result != MACH_MSG_SUCCESS)
{ return check_result; }
#endif /* defined(__MIG_check__Reply__mach_exception_raise_state_t__defined) */
*flavor = Out0P->flavor;
if (Out0P->new_stateCnt > 224) {
(void)memcpy((char *) new_state, (const char *) Out0P->new_state, 4 * 224);
*new_stateCnt = Out0P->new_stateCnt;
{ return MIG_ARRAY_TOO_LARGE; }
}
(void)memcpy((char *) new_state, (const char *) Out0P->new_state, 4 * Out0P->new_stateCnt);
*new_stateCnt = Out0P->new_stateCnt;
return KERN_SUCCESS;
}
#if ( __MigTypeCheck )
#if __MIG_check__Reply__mach_exc_subsystem__
#if !defined(__MIG_check__Reply__mach_exception_raise_state_identity_t__defined)
#define __MIG_check__Reply__mach_exception_raise_state_identity_t__defined
mig_internal kern_return_t __MIG_check__Reply__mach_exception_raise_state_identity_t(__Reply__mach_exception_raise_state_identity_t *Out0P)
{
typedef __Reply__mach_exception_raise_state_identity_t __Reply;
#if __MigTypeCheck
unsigned int msgh_size;
#endif /* __MigTypeCheck */
if (Out0P->Head.msgh_id != 2507) {
if (Out0P->Head.msgh_id == MACH_NOTIFY_SEND_ONCE)
{ return MIG_SERVER_DIED; }
else
{ return MIG_REPLY_MISMATCH; }
}
#if __MigTypeCheck
msgh_size = Out0P->Head.msgh_size;
if ((Out0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||
((msgh_size > (mach_msg_size_t)sizeof(__Reply) || msgh_size < (mach_msg_size_t)(sizeof(__Reply) - 896)) &&
(msgh_size != (mach_msg_size_t)sizeof(mig_reply_error_t) ||
Out0P->RetCode == KERN_SUCCESS)))
{ return MIG_TYPE_ERROR ; }
#endif /* __MigTypeCheck */
if (Out0P->RetCode != KERN_SUCCESS) {
return ((mig_reply_error_t *)Out0P)->RetCode;
}
#if __MigTypeCheck
if ( Out0P->new_stateCnt > 224 )
return MIG_TYPE_ERROR;
if (((msgh_size - (mach_msg_size_t)(sizeof(__Reply) - 896)) / 4< Out0P->new_stateCnt) ||
(msgh_size != (mach_msg_size_t)(sizeof(__Reply) - 896) + Out0P->new_stateCnt * 4))
{ return MIG_TYPE_ERROR ; }
#endif /* __MigTypeCheck */
return MACH_MSG_SUCCESS;
}
#endif /* !defined(__MIG_check__Reply__mach_exception_raise_state_identity_t__defined) */
#endif /* __MIG_check__Reply__mach_exc_subsystem__ */
#endif /* ( __MigTypeCheck ) */
/* Routine mach_exception_raise_state_identity */
mig_external kern_return_t mach_exception_raise_state_identity
(
mach_port_t exception_port,
mach_port_t thread,
mach_port_t task,
exception_type_t exception,
mach_exception_data_t code,
mach_msg_type_number_t codeCnt,
int *flavor,
thread_state_t old_state,
mach_msg_type_number_t old_stateCnt,
thread_state_t new_state,
mach_msg_type_number_t *new_stateCnt
)
{
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t thread;
mach_msg_port_descriptor_t task;
/* end of the kernel processed data */
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;
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
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];
mach_msg_trailer_t trailer;
} Reply;
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
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;
#ifdef __MigPackStructs
#pragma pack()
#endif
/*
* typedef struct {
* mach_msg_header_t Head;
* NDR_record_t NDR;
* kern_return_t RetCode;
* } mig_reply_error_t;
*/
union {
Request In;
Reply Out;
} Mess;
Request *InP = &Mess.In;
Reply *Out0P = &Mess.Out;
mach_msg_return_t msg_result;
unsigned int msgh_size;
unsigned int msgh_size_delta;
#ifdef __MIG_check__Reply__mach_exception_raise_state_identity_t__defined
kern_return_t check_result;
#endif /* __MIG_check__Reply__mach_exception_raise_state_identity_t__defined */
__DeclareSendRpc(2407, "mach_exception_raise_state_identity")
#if UseStaticTemplates
const static mach_msg_port_descriptor_t threadTemplate = {
/* name = */ MACH_PORT_NULL,
/* pad1 = */ 0,
/* pad2 = */ 0,
/* disp = */ 19,
/* type = */ MACH_MSG_PORT_DESCRIPTOR,
};
#endif /* UseStaticTemplates */
#if UseStaticTemplates
const static mach_msg_port_descriptor_t taskTemplate = {
/* name = */ MACH_PORT_NULL,
/* pad1 = */ 0,
/* pad2 = */ 0,
/* disp = */ 19,
/* type = */ MACH_MSG_PORT_DESCRIPTOR,
};
#endif /* UseStaticTemplates */
InP->msgh_body.msgh_descriptor_count = 2;
#if UseStaticTemplates
InP->thread = threadTemplate;
InP->thread.name = thread;
#else /* UseStaticTemplates */
InP->thread.name = thread;
InP->thread.disposition = 19;
InP->thread.type = MACH_MSG_PORT_DESCRIPTOR;
#endif /* UseStaticTemplates */
#if UseStaticTemplates
InP->task = taskTemplate;
InP->task.name = task;
#else /* UseStaticTemplates */
InP->task.name = task;
InP->task.disposition = 19;
InP->task.type = MACH_MSG_PORT_DESCRIPTOR;
#endif /* UseStaticTemplates */
InP->NDR = NDR_record;
InP->exception = exception;
if (codeCnt > 2) {
{ return MIG_ARRAY_TOO_LARGE; }
}
(void)memcpy((char *) InP->code, (const char *) code, 8 * codeCnt);
InP->codeCnt = codeCnt;
msgh_size_delta = (8 * codeCnt);
msgh_size = (mach_msg_size_t)(sizeof(Request) - 912) + msgh_size_delta;
InP = (Request *) ((pointer_t) InP + msgh_size_delta - 16);
InP->flavor = *flavor;
if (old_stateCnt > 224) {
{ return MIG_ARRAY_TOO_LARGE; }
}
(void)memcpy((char *) InP->old_state, (const char *) old_state, 4 * old_stateCnt);
InP->old_stateCnt = old_stateCnt;
msgh_size += (4 * old_stateCnt);
InP = &Mess.In;
InP->Head.msgh_bits = MACH_MSGH_BITS_COMPLEX|
MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);
/* msgh_size passed as argument */
InP->Head.msgh_request_port = exception_port;
InP->Head.msgh_reply_port = mig_get_reply_port();
InP->Head.msgh_id = 2407;
/* BEGIN VOUCHER CODE */
#ifdef USING_VOUCHERS
if (voucher_mach_msg_set != NULL) {
voucher_mach_msg_set(&InP->Head);
}
#endif // USING_VOUCHERS
/* END VOUCHER CODE */
__BeforeSendRpc(2407, "mach_exception_raise_state_identity")
msg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, msgh_size, (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
__AfterSendRpc(2407, "mach_exception_raise_state_identity")
if (msg_result != MACH_MSG_SUCCESS) {
__MachMsgErrorWithoutTimeout(msg_result);
{ return msg_result; }
}
#if defined(__MIG_check__Reply__mach_exception_raise_state_identity_t__defined)
check_result = __MIG_check__Reply__mach_exception_raise_state_identity_t((__Reply__mach_exception_raise_state_identity_t *)Out0P);
if (check_result != MACH_MSG_SUCCESS)
{ return check_result; }
#endif /* defined(__MIG_check__Reply__mach_exception_raise_state_identity_t__defined) */
*flavor = Out0P->flavor;
if (Out0P->new_stateCnt > 224) {
(void)memcpy((char *) new_state, (const char *) Out0P->new_state, 4 * 224);
*new_stateCnt = Out0P->new_stateCnt;
{ return MIG_ARRAY_TOO_LARGE; }
}
(void)memcpy((char *) new_state, (const char *) Out0P->new_state, 4 * Out0P->new_stateCnt);
*new_stateCnt = Out0P->new_stateCnt;
return KERN_SUCCESS;
}

View File

@ -0,0 +1,132 @@
//+build darwin,!macnative
package native
import (
"errors"
"sync"
"github.com/go-delve/delve/pkg/proc"
)
var ErrNativeBackendDisabled = errors.New("native backend disabled during compilation")
// Launch returns ErrNativeBackendDisabled.
func Launch(cmd []string, wd string, foreground bool, _ []string) (*Process, error) {
return nil, ErrNativeBackendDisabled
}
// Attach returns ErrNativeBackendDisabled.
func Attach(pid int, _ []string) (*Process, error) {
return nil, ErrNativeBackendDisabled
}
// WaitStatus is a synonym for the platform-specific WaitStatus
type WaitStatus struct{}
// OSSpecificDetails holds information specific to the OSX/Darwin
// operating system / kernel.
type OSSpecificDetails struct{}
// OSProcessDetails holds Darwin specific information.
type OSProcessDetails struct{}
func findExecutable(path string, pid int) string {
panic(ErrNativeBackendDisabled)
}
func killProcess(pid int) error {
panic(ErrNativeBackendDisabled)
}
func registers(thread *Thread, floatingPoint bool) (proc.Registers, error) {
panic(ErrNativeBackendDisabled)
}
func (dbp *Process) loadProcessInformation(wg *sync.WaitGroup) {
panic(ErrNativeBackendDisabled)
}
func (dbp *Process) requestManualStop() (err error) {
panic(ErrNativeBackendDisabled)
}
func (dbp *Process) resume() error {
panic(ErrNativeBackendDisabled)
}
func (dbp *Process) trapWait(pid int) (*Thread, error) {
panic(ErrNativeBackendDisabled)
}
func (dbp *Process) stop(trapthread *Thread) (err error) {
panic(ErrNativeBackendDisabled)
}
func (dbp *Process) updateThreadList() error {
panic(ErrNativeBackendDisabled)
}
func (dbp *Process) kill() (err error) {
panic(ErrNativeBackendDisabled)
}
func (dbp *Process) detach(kill bool) error {
panic(ErrNativeBackendDisabled)
}
// EntryPoint returns the entry point for the process,
// useful for PIEs.
func (dbp *Process) EntryPoint() (uint64, error) {
panic(ErrNativeBackendDisabled)
}
// Blocked returns true if the thread is blocked
func (t *Thread) Blocked() bool {
panic(ErrNativeBackendDisabled)
}
// SetPC sets the value of the PC register.
func (t *Thread) SetPC(pc uint64) error {
panic(ErrNativeBackendDisabled)
}
// SetSP sets the value of the SP register.
func (t *Thread) SetSP(sp uint64) error {
panic(ErrNativeBackendDisabled)
}
// SetDX sets the value of the DX register.
func (t *Thread) SetDX(dx uint64) error {
panic(ErrNativeBackendDisabled)
}
// ReadMemory reads len(buf) bytes at addr into buf.
func (t *Thread) ReadMemory(buf []byte, addr uintptr) (int, error) {
panic(ErrNativeBackendDisabled)
}
// WriteMemory writes the contents of data at addr.
func (t *Thread) WriteMemory(addr uintptr, data []byte) (int, error) {
panic(ErrNativeBackendDisabled)
}
func (t *Thread) resume() error {
panic(ErrNativeBackendDisabled)
}
func (t *Thread) singleStep() error {
panic(ErrNativeBackendDisabled)
}
func (t *Thread) restoreRegisters(sr proc.Registers) error {
panic(ErrNativeBackendDisabled)
}
// Stopped returns whether the thread is stopped at
// the operating system level.
func (t *Thread) Stopped() bool {
panic(ErrNativeBackendDisabled)
}
func initialize(dbp *Process) error { return nil }

View File

@ -0,0 +1,422 @@
package native
import (
"fmt"
"go/ast"
"runtime"
"sync"
"github.com/go-delve/delve/pkg/proc"
)
// Process represents all of the information the debugger
// is holding onto regarding the process we are debugging.
type Process struct {
bi *proc.BinaryInfo
pid int // Process Pid
// Breakpoint table, holds information on breakpoints.
// Maps instruction address to Breakpoint struct.
breakpoints proc.BreakpointMap
// List of threads mapped as such: pid -> *Thread
threads map[int]*Thread
// Active thread
currentThread *Thread
// Goroutine that will be used by default to set breakpoint, eval variables, etc...
// Normally selectedGoroutine is currentThread.GetG, it will not be only if SwitchGoroutine is called with a goroutine that isn't attached to a thread
selectedGoroutine *proc.G
common proc.CommonProcess
os *OSProcessDetails
firstStart bool
stopMu sync.Mutex
resumeChan chan<- struct{}
ptraceChan chan func()
ptraceDoneChan chan interface{}
childProcess bool // this process was launched, not attached to
manualStopRequested bool
exited, detached bool
}
// New returns an initialized Process struct. Before returning,
// it will also launch a goroutine in order to handle ptrace(2)
// functions. For more information, see the documentation on
// `handlePtraceFuncs`.
func New(pid int) *Process {
dbp := &Process{
pid: pid,
threads: make(map[int]*Thread),
breakpoints: proc.NewBreakpointMap(),
firstStart: true,
os: new(OSProcessDetails),
ptraceChan: make(chan func()),
ptraceDoneChan: make(chan interface{}),
bi: proc.NewBinaryInfo(runtime.GOOS, runtime.GOARCH),
}
go dbp.handlePtraceFuncs()
return dbp
}
// BinInfo will return the binary info struct associated with this process.
func (dbp *Process) BinInfo() *proc.BinaryInfo {
return dbp.bi
}
// Recorded always returns false for the native proc backend.
func (dbp *Process) Recorded() (bool, string) { return false, "" }
// Restart will always return an error in the native proc backend, only for
// recorded traces.
func (dbp *Process) Restart(string) error { return proc.ErrNotRecorded }
// Direction will always return an error in the native proc backend, only for
// recorded traces.
func (dbp *Process) Direction(proc.Direction) error { return proc.ErrNotRecorded }
// When will always return an empty string and nil, not supported on native proc backend.
func (dbp *Process) When() (string, error) { return "", nil }
// Checkpoint will always return an error on the native proc backend,
// only supported for recorded traces.
func (dbp *Process) Checkpoint(string) (int, error) { return -1, proc.ErrNotRecorded }
// Checkpoints will always return an error on the native proc backend,
// only supported for recorded traces.
func (dbp *Process) Checkpoints() ([]proc.Checkpoint, error) { return nil, proc.ErrNotRecorded }
// ClearCheckpoint will always return an error on the native proc backend,
// only supported in recorded traces.
func (dbp *Process) ClearCheckpoint(int) error { return proc.ErrNotRecorded }
// Detach from the process being debugged, optionally killing it.
func (dbp *Process) Detach(kill bool) (err error) {
if dbp.exited {
return nil
}
if kill && dbp.childProcess {
err := dbp.kill()
if err != nil {
return err
}
dbp.bi.Close()
return nil
}
if !kill {
// Clean up any breakpoints we've set.
for _, bp := range dbp.breakpoints.M {
if bp != nil {
_, err := dbp.ClearBreakpoint(bp.Addr)
if err != nil {
return err
}
}
}
}
dbp.execPtraceFunc(func() {
err = dbp.detach(kill)
if err != nil {
return
}
if kill {
err = killProcess(dbp.pid)
}
})
dbp.detached = true
dbp.postExit()
return
}
// Valid returns whether the process is still attached to and
// has not exited.
func (dbp *Process) Valid() (bool, error) {
if dbp.detached {
return false, &proc.ProcessDetachedError{}
}
if dbp.exited {
return false, &proc.ErrProcessExited{Pid: dbp.Pid()}
}
return true, nil
}
// ResumeNotify specifies a channel that will be closed the next time
// ContinueOnce finishes resuming the target.
func (dbp *Process) ResumeNotify(ch chan<- struct{}) {
dbp.resumeChan = ch
}
// Pid returns the process ID.
func (dbp *Process) Pid() int {
return dbp.pid
}
// SelectedGoroutine returns the current selected,
// active goroutine.
func (dbp *Process) SelectedGoroutine() *proc.G {
return dbp.selectedGoroutine
}
// ThreadList returns a list of threads in the process.
func (dbp *Process) ThreadList() []proc.Thread {
r := make([]proc.Thread, 0, len(dbp.threads))
for _, v := range dbp.threads {
r = append(r, v)
}
return r
}
// FindThread attempts to find the thread with the specified ID.
func (dbp *Process) FindThread(threadID int) (proc.Thread, bool) {
th, ok := dbp.threads[threadID]
return th, ok
}
// CurrentThread returns the current selected, active thread.
func (dbp *Process) CurrentThread() proc.Thread {
return dbp.currentThread
}
// Breakpoints returns a list of breakpoints currently set.
func (dbp *Process) Breakpoints() *proc.BreakpointMap {
return &dbp.breakpoints
}
// RequestManualStop sets the `halt` flag and
// sends SIGSTOP to all threads.
func (dbp *Process) RequestManualStop() error {
if dbp.exited {
return &proc.ErrProcessExited{Pid: dbp.Pid()}
}
dbp.stopMu.Lock()
defer dbp.stopMu.Unlock()
dbp.manualStopRequested = true
return dbp.requestManualStop()
}
// CheckAndClearManualStopRequest checks if a manual stop has
// been requested, and then clears that state.
func (dbp *Process) CheckAndClearManualStopRequest() bool {
dbp.stopMu.Lock()
defer dbp.stopMu.Unlock()
msr := dbp.manualStopRequested
dbp.manualStopRequested = false
return msr
}
func (dbp *Process) writeBreakpoint(addr uint64) (string, int, *proc.Function, []byte, error) {
f, l, fn := dbp.bi.PCToLine(uint64(addr))
originalData := make([]byte, dbp.bi.Arch.BreakpointSize())
_, err := dbp.currentThread.ReadMemory(originalData, uintptr(addr))
if err != nil {
return "", 0, nil, nil, err
}
if err := dbp.writeSoftwareBreakpoint(dbp.currentThread, addr); err != nil {
return "", 0, nil, nil, err
}
return f, l, fn, originalData, nil
}
// SetBreakpoint sets a breakpoint at addr, and stores it in the process wide
// break point table.
func (dbp *Process) SetBreakpoint(addr uint64, kind proc.BreakpointKind, cond ast.Expr) (*proc.Breakpoint, error) {
return dbp.breakpoints.Set(addr, kind, cond, dbp.writeBreakpoint)
}
// ClearBreakpoint clears the breakpoint at addr.
func (dbp *Process) ClearBreakpoint(addr uint64) (*proc.Breakpoint, error) {
if dbp.exited {
return nil, &proc.ErrProcessExited{Pid: dbp.Pid()}
}
return dbp.breakpoints.Clear(addr, dbp.currentThread.ClearBreakpoint)
}
// ContinueOnce will continue the target until it stops.
// This could be the result of a breakpoint or signal.
func (dbp *Process) ContinueOnce() (proc.Thread, error) {
if dbp.exited {
return nil, &proc.ErrProcessExited{Pid: dbp.Pid()}
}
if err := dbp.resume(); err != nil {
return nil, err
}
dbp.common.ClearAllGCache()
for _, th := range dbp.threads {
th.CurrentBreakpoint.Clear()
}
if dbp.resumeChan != nil {
close(dbp.resumeChan)
dbp.resumeChan = nil
}
trapthread, err := dbp.trapWait(-1)
if err != nil {
return nil, err
}
if err := dbp.stop(trapthread); err != nil {
return nil, err
}
return trapthread, err
}
// StepInstruction will continue the current thread for exactly
// one instruction. This method affects only the thread
// associated with the selected goroutine. All other
// threads will remain stopped.
func (dbp *Process) StepInstruction() (err error) {
thread := dbp.currentThread
if dbp.selectedGoroutine != nil {
if dbp.selectedGoroutine.Thread == nil {
// Step called on parked goroutine
if _, err := dbp.SetBreakpoint(dbp.selectedGoroutine.PC, proc.NextBreakpoint, proc.SameGoroutineCondition(dbp.selectedGoroutine)); err != nil {
return err
}
return proc.Continue(dbp)
}
thread = dbp.selectedGoroutine.Thread.(*Thread)
}
dbp.common.ClearAllGCache()
if dbp.exited {
return &proc.ErrProcessExited{Pid: dbp.Pid()}
}
thread.CurrentBreakpoint.Clear()
err = thread.StepInstruction()
if err != nil {
return err
}
err = thread.SetCurrentBreakpoint()
if err != nil {
return err
}
if g, _ := proc.GetG(thread); g != nil {
dbp.selectedGoroutine = g
}
return nil
}
// SwitchThread changes from current thread to the thread specified by `tid`.
func (dbp *Process) SwitchThread(tid int) error {
if dbp.exited {
return &proc.ErrProcessExited{Pid: dbp.Pid()}
}
if th, ok := dbp.threads[tid]; ok {
dbp.currentThread = th
dbp.selectedGoroutine, _ = proc.GetG(dbp.currentThread)
return nil
}
return fmt.Errorf("thread %d does not exist", tid)
}
// SwitchGoroutine changes from current thread to the thread
// running the specified goroutine.
func (dbp *Process) SwitchGoroutine(gid int) error {
if dbp.exited {
return &proc.ErrProcessExited{Pid: dbp.Pid()}
}
g, err := proc.FindGoroutine(dbp, gid)
if err != nil {
return err
}
if g == nil {
// user specified -1 and selectedGoroutine is nil
return nil
}
if g.Thread != nil {
return dbp.SwitchThread(g.Thread.ThreadID())
}
dbp.selectedGoroutine = g
return nil
}
// FindBreakpoint finds the breakpoint for the given pc.
func (dbp *Process) FindBreakpoint(pc uint64) (*proc.Breakpoint, bool) {
// Check to see if address is past the breakpoint, (i.e. breakpoint was hit).
if bp, ok := dbp.breakpoints.M[pc-uint64(dbp.bi.Arch.BreakpointSize())]; ok {
return bp, true
}
// Directly use addr to lookup breakpoint.
if bp, ok := dbp.breakpoints.M[pc]; ok {
return bp, true
}
return nil, false
}
// initialize will ensure that all relevant information is loaded
// so the process is ready to be debugged.
func (dbp *Process) initialize(path string, debugInfoDirs []string) error {
if err := initialize(dbp); err != nil {
return err
}
if err := dbp.updateThreadList(); err != nil {
return err
}
return proc.PostInitializationSetup(dbp, path, debugInfoDirs, dbp.writeBreakpoint)
}
// SetSelectedGoroutine will set internally the goroutine that should be
// the default for any command executed, the goroutine being actively
// followed.
func (dbp *Process) SetSelectedGoroutine(g *proc.G) {
dbp.selectedGoroutine = g
}
// ClearInternalBreakpoints will clear all non-user set breakpoints. These
// breakpoints are set for internal operations such as 'next'.
func (dbp *Process) ClearInternalBreakpoints() error {
return dbp.breakpoints.ClearInternalBreakpoints(func(bp *proc.Breakpoint) error {
if err := dbp.currentThread.ClearBreakpoint(bp); err != nil {
return err
}
for _, thread := range dbp.threads {
if thread.CurrentBreakpoint.Breakpoint == bp {
thread.CurrentBreakpoint.Clear()
}
}
return nil
})
}
func (dbp *Process) handlePtraceFuncs() {
// We must ensure here that we are running on the same thread during
// while invoking the ptrace(2) syscall. This is due to the fact that ptrace(2) expects
// all commands after PTRACE_ATTACH to come from the same thread.
runtime.LockOSThread()
for fn := range dbp.ptraceChan {
fn()
dbp.ptraceDoneChan <- nil
}
}
func (dbp *Process) execPtraceFunc(fn func()) {
dbp.ptraceChan <- fn
<-dbp.ptraceDoneChan
}
func (dbp *Process) postExit() {
dbp.exited = true
close(dbp.ptraceChan)
close(dbp.ptraceDoneChan)
dbp.bi.Close()
}
func (dbp *Process) writeSoftwareBreakpoint(thread *Thread, addr uint64) error {
_, err := thread.WriteMemory(uintptr(addr), dbp.bi.Arch.BreakpointInstruction())
return err
}
// Common returns common information across Process
// implementations
func (dbp *Process) Common() *proc.CommonProcess {
return &dbp.common
}

View File

@ -0,0 +1,233 @@
//+build darwin,macnative
#include "proc_darwin.h"
static const unsigned char info_plist[]
__attribute__ ((section ("__TEXT,__info_plist"),used)) =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\""
" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
"<plist version=\"1.0\">\n"
"<dict>\n"
" <key>CFBundleIdentifier</key>\n"
" <string>org.dlv</string>\n"
" <key>CFBundleName</key>\n"
" <string>delve</string>\n"
" <key>CFBundleVersion</key>\n"
" <string>1.0</string>\n"
" <key>SecTaskAccess</key>\n"
" <array>\n"
" <string>allowed</string>\n"
" <string>debug</string>\n"
" </array>\n"
"</dict>\n"
"</plist>\n";
kern_return_t
acquire_mach_task(int tid,
task_t *task,
mach_port_t *port_set,
mach_port_t *exception_port,
mach_port_t *notification_port)
{
kern_return_t kret;
mach_port_t prev_not;
mach_port_t self = mach_task_self();
kret = task_for_pid(self, tid, task);
if (kret != KERN_SUCCESS) return kret;
// Allocate exception port.
kret = mach_port_allocate(self, MACH_PORT_RIGHT_RECEIVE, exception_port);
if (kret != KERN_SUCCESS) return kret;
kret = mach_port_insert_right(self, *exception_port, *exception_port, MACH_MSG_TYPE_MAKE_SEND);
if (kret != KERN_SUCCESS) return kret;
kret = task_set_exception_ports(*task, EXC_MASK_BREAKPOINT|EXC_MASK_SOFTWARE, *exception_port,
EXCEPTION_DEFAULT, THREAD_STATE_NONE);
if (kret != KERN_SUCCESS) return kret;
// Allocate notification port to alert of when the process dies.
kret = mach_port_allocate(self, MACH_PORT_RIGHT_RECEIVE, notification_port);
if (kret != KERN_SUCCESS) return kret;
kret = mach_port_insert_right(self, *notification_port, *notification_port, MACH_MSG_TYPE_MAKE_SEND);
if (kret != KERN_SUCCESS) return kret;
kret = mach_port_request_notification(self, *task, MACH_NOTIFY_DEAD_NAME, 0, *notification_port,
MACH_MSG_TYPE_MAKE_SEND_ONCE, &prev_not);
if (kret != KERN_SUCCESS) return kret;
// Create port set.
kret = mach_port_allocate(self, MACH_PORT_RIGHT_PORT_SET, port_set);
if (kret != KERN_SUCCESS) return kret;
// Move exception and notification ports to port set.
kret = mach_port_move_member(self, *exception_port, *port_set);
if (kret != KERN_SUCCESS) return kret;
return mach_port_move_member(self, *notification_port, *port_set);
}
kern_return_t
reset_exception_ports(task_t task, mach_port_t *exception_port, mach_port_t *notification_port) {
kern_return_t kret;
mach_port_t prev_not;
mach_port_t self = mach_task_self();
kret = task_set_exception_ports(task, EXC_MASK_BREAKPOINT|EXC_MASK_SOFTWARE, *exception_port,
EXCEPTION_DEFAULT, THREAD_STATE_NONE);
if (kret != KERN_SUCCESS) return kret;
kret = mach_port_request_notification(self, task, MACH_NOTIFY_DEAD_NAME, 0, *notification_port,
MACH_MSG_TYPE_MAKE_SEND_ONCE, &prev_not);
if (kret != KERN_SUCCESS) return kret;
return KERN_SUCCESS;
}
char *
find_executable(int pid) {
static char pathbuf[PATH_MAX];
proc_pidpath(pid, pathbuf, PATH_MAX);
return pathbuf;
}
kern_return_t
get_threads(task_t task, void *slice, int limit) {
kern_return_t kret;
thread_act_array_t list;
mach_msg_type_number_t count;
kret = task_threads(task, &list, &count);
if (kret != KERN_SUCCESS) {
return kret;
}
if (count > limit) {
vm_deallocate(mach_task_self(), (vm_address_t) list, count * sizeof(list[0]));
return -2;
}
memcpy(slice, (void*)list, count*sizeof(list[0]));
kret = vm_deallocate(mach_task_self(), (vm_address_t) list, count * sizeof(list[0]));
if (kret != KERN_SUCCESS) return kret;
return (kern_return_t)0;
}
int
thread_count(task_t task) {
kern_return_t kret;
thread_act_array_t list;
mach_msg_type_number_t count;
kret = task_threads(task, &list, &count);
if (kret != KERN_SUCCESS) return -1;
kret = vm_deallocate(mach_task_self(), (vm_address_t) list, count * sizeof(list[0]));
if (kret != KERN_SUCCESS) return -1;
return count;
}
mach_port_t
mach_port_wait(mach_port_t port_set, task_t *task, int nonblocking) {
kern_return_t kret;
thread_act_t thread;
NDR_record_t *ndr;
integer_t *data;
union
{
mach_msg_header_t hdr;
char data[256];
} msg;
mach_msg_option_t opts = MACH_RCV_MSG|MACH_RCV_INTERRUPT;
if (nonblocking) {
opts |= MACH_RCV_TIMEOUT;
}
// Wait for mach msg.
kret = mach_msg(&msg.hdr, opts,
0, sizeof(msg.data), port_set, 10, MACH_PORT_NULL);
if (kret == MACH_RCV_INTERRUPTED) return kret;
if (kret != MACH_MSG_SUCCESS) return 0;
switch (msg.hdr.msgh_id) {
case 2401: { // Exception
// 2401 is the exception_raise event, defined in:
// http://opensource.apple.com/source/xnu/xnu-2422.1.72/osfmk/mach/exc.defs?txt
// compile this file with mig to get the C version of the description
mach_msg_body_t *bod = (mach_msg_body_t*)(&msg.hdr + 1);
mach_msg_port_descriptor_t *desc = (mach_msg_port_descriptor_t *)(bod + 1);
thread = desc[0].name;
*task = desc[1].name;
ndr = (NDR_record_t *)(desc + 2);
data = (integer_t *)(ndr + 1);
if (thread_suspend(thread) != KERN_SUCCESS) return 0;
// Send our reply back so the kernel knows this exception has been handled.
kret = mach_send_reply(msg.hdr);
if (kret != MACH_MSG_SUCCESS) return 0;
if (data[2] == EXC_SOFT_SIGNAL) {
if (data[3] != SIGTRAP) {
if (thread_resume(thread) != KERN_SUCCESS) return 0;
return mach_port_wait(port_set, task, nonblocking);
}
}
return thread;
}
case 72: { // Death
// 72 is mach_notify_dead_name, defined in:
// https://opensource.apple.com/source/xnu/xnu-1228.7.58/osfmk/mach/notify.defs?txt
// compile this file with mig to get the C version of the description
ndr = (NDR_record_t *)(&msg.hdr + 1);
*task = *((mach_port_name_t *)(ndr + 1));
return msg.hdr.msgh_local_port;
}
}
return 0;
}
kern_return_t
mach_send_reply(mach_msg_header_t hdr) {
mig_reply_error_t reply;
mach_msg_header_t *rh = &reply.Head;
rh->msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(hdr.msgh_bits), 0);
rh->msgh_remote_port = hdr.msgh_remote_port;
rh->msgh_size = (mach_msg_size_t) sizeof(mig_reply_error_t);
rh->msgh_local_port = MACH_PORT_NULL;
rh->msgh_id = hdr.msgh_id + 100;
reply.NDR = NDR_record;
reply.RetCode = KERN_SUCCESS;
return mach_msg(&reply.Head, MACH_SEND_MSG|MACH_SEND_INTERRUPT, rh->msgh_size, 0,
MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
}
kern_return_t
raise_exception(mach_port_t task, mach_port_t thread, mach_port_t exception_port, exception_type_t exception) {
return exception_raise(exception_port, thread, task, exception, 0, 0);
}
task_t
get_task_for_pid(int pid) {
task_t task = 0;
mach_port_t self = mach_task_self();
task_for_pid(self, pid, &task);
return task;
}
int
task_is_valid(task_t task) {
struct task_basic_info info;
mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT;
return task_info(task, TASK_BASIC_INFO, (task_info_t)&info, &count) == KERN_SUCCESS;
}

View File

@ -0,0 +1,467 @@
//+build darwin,macnative
package native
// #include "proc_darwin.h"
// #include "threads_darwin.h"
// #include "exec_darwin.h"
// #include <stdlib.h>
import "C"
import (
"errors"
"fmt"
"os"
"os/exec"
"path/filepath"
"unsafe"
sys "golang.org/x/sys/unix"
"github.com/go-delve/delve/pkg/proc"
)
// OSProcessDetails holds Darwin specific information.
type OSProcessDetails struct {
task C.task_t // mach task for the debugged process.
exceptionPort C.mach_port_t // mach port for receiving mach exceptions.
notificationPort C.mach_port_t // mach port for dead name notification (process exit).
initialized bool
halt bool
// the main port we use, will return messages from both the
// exception and notification ports.
portSet C.mach_port_t
}
// Launch creates and begins debugging a new process. Uses a
// custom fork/exec process in order to take advantage of
// PT_SIGEXC on Darwin which will turn Unix signals into
// Mach exceptions.
func Launch(cmd []string, wd string, foreground bool, _ []string) (*Process, error) {
// check that the argument to Launch is an executable file
if fi, staterr := os.Stat(cmd[0]); staterr == nil && (fi.Mode()&0111) == 0 {
return nil, proc.ErrNotExecutable
}
argv0Go, err := filepath.Abs(cmd[0])
if err != nil {
return nil, err
}
// Make sure the binary exists.
if filepath.Base(cmd[0]) == cmd[0] {
if _, err := exec.LookPath(cmd[0]); err != nil {
return nil, err
}
}
if _, err := os.Stat(argv0Go); err != nil {
return nil, err
}
argv0 := C.CString(argv0Go)
argvSlice := make([]*C.char, 0, len(cmd)+1)
for _, arg := range cmd {
argvSlice = append(argvSlice, C.CString(arg))
}
// argv array must be null terminated.
argvSlice = append(argvSlice, nil)
dbp := New(0)
var pid int
dbp.execPtraceFunc(func() {
ret := C.fork_exec(argv0, &argvSlice[0], C.int(len(argvSlice)),
C.CString(wd),
&dbp.os.task, &dbp.os.portSet, &dbp.os.exceptionPort,
&dbp.os.notificationPort)
pid = int(ret)
})
if pid <= 0 {
return nil, fmt.Errorf("could not fork/exec")
}
dbp.pid = pid
dbp.childProcess = true
for i := range argvSlice {
C.free(unsafe.Pointer(argvSlice[i]))
}
// Initialize enough of the Process state so that we can use resume and
// trapWait to wait until the child process calls execve.
for {
task := C.get_task_for_pid(C.int(dbp.pid))
// The task_for_pid call races with the fork call. This can
// result in the parent task being returned instead of the child.
if task != dbp.os.task {
err = dbp.updateThreadListForTask(task)
if err == nil {
break
}
if err != couldNotGetThreadCount && err != couldNotGetThreadList {
return nil, err
}
}
}
if err := dbp.resume(); err != nil {
return nil, err
}
dbp.common.ClearAllGCache()
for _, th := range dbp.threads {
th.CurrentBreakpoint.Clear()
}
trapthread, err := dbp.trapWait(-1)
if err != nil {
return nil, err
}
if err := dbp.stop(nil); err != nil {
return nil, err
}
dbp.os.initialized = true
err = dbp.initialize(argv0Go, []string{})
if err != nil {
return nil, err
}
if err := dbp.SwitchThread(trapthread.ID); err != nil {
return nil, err
}
return dbp, err
}
// Attach to an existing process with the given PID.
func Attach(pid int, _ []string) (*Process, error) {
dbp := New(pid)
kret := C.acquire_mach_task(C.int(pid),
&dbp.os.task, &dbp.os.portSet, &dbp.os.exceptionPort,
&dbp.os.notificationPort)
if kret != C.KERN_SUCCESS {
return nil, fmt.Errorf("could not attach to %d", pid)
}
dbp.os.initialized = true
var err error
dbp.execPtraceFunc(func() { err = PtraceAttach(dbp.pid) })
if err != nil {
return nil, err
}
_, _, err = dbp.wait(dbp.pid, 0)
if err != nil {
return nil, err
}
err = dbp.initialize("", []string{})
if err != nil {
dbp.Detach(false)
return nil, err
}
return dbp, nil
}
// Kill kills the process.
func (dbp *Process) kill() (err error) {
if dbp.exited {
return nil
}
err = sys.Kill(-dbp.pid, sys.SIGKILL)
if err != nil {
return errors.New("could not deliver signal: " + err.Error())
}
for port := range dbp.threads {
if C.thread_resume(C.thread_act_t(port)) != C.KERN_SUCCESS {
return errors.New("could not resume task")
}
}
for {
var task C.task_t
port := C.mach_port_wait(dbp.os.portSet, &task, C.int(0))
if port == dbp.os.notificationPort {
break
}
}
dbp.postExit()
return
}
func (dbp *Process) requestManualStop() (err error) {
var (
task = C.mach_port_t(dbp.os.task)
thread = C.mach_port_t(dbp.currentThread.os.threadAct)
exceptionPort = C.mach_port_t(dbp.os.exceptionPort)
)
dbp.os.halt = true
kret := C.raise_exception(task, thread, exceptionPort, C.EXC_BREAKPOINT)
if kret != C.KERN_SUCCESS {
return fmt.Errorf("could not raise mach exception")
}
return nil
}
var couldNotGetThreadCount = errors.New("could not get thread count")
var couldNotGetThreadList = errors.New("could not get thread list")
func (dbp *Process) updateThreadList() error {
return dbp.updateThreadListForTask(dbp.os.task)
}
func (dbp *Process) updateThreadListForTask(task C.task_t) error {
var (
err error
kret C.kern_return_t
count C.int
list []uint32
)
for {
count = C.thread_count(task)
if count == -1 {
return couldNotGetThreadCount
}
list = make([]uint32, count)
// TODO(dp) might be better to malloc mem in C and then free it here
// instead of getting count above and passing in a slice
kret = C.get_threads(task, unsafe.Pointer(&list[0]), count)
if kret != -2 {
break
}
}
if kret != C.KERN_SUCCESS {
return couldNotGetThreadList
}
for _, thread := range dbp.threads {
thread.os.exists = false
}
for _, port := range list {
thread, ok := dbp.threads[int(port)]
if !ok {
thread, err = dbp.addThread(int(port), false)
if err != nil {
return err
}
}
thread.os.exists = true
}
for threadID, thread := range dbp.threads {
if !thread.os.exists {
delete(dbp.threads, threadID)
}
}
return nil
}
func (dbp *Process) addThread(port int, attach bool) (*Thread, error) {
if thread, ok := dbp.threads[port]; ok {
return thread, nil
}
thread := &Thread{
ID: port,
dbp: dbp,
os: new(OSSpecificDetails),
}
dbp.threads[port] = thread
thread.os.threadAct = C.thread_act_t(port)
if dbp.currentThread == nil {
dbp.SwitchThread(thread.ID)
}
return thread, nil
}
func findExecutable(path string, pid int) string {
if path == "" {
path = C.GoString(C.find_executable(C.int(pid)))
}
return path
}
func (dbp *Process) trapWait(pid int) (*Thread, error) {
for {
task := dbp.os.task
port := C.mach_port_wait(dbp.os.portSet, &task, C.int(0))
switch port {
case dbp.os.notificationPort:
// on macOS >= 10.12.1 the task_t changes after an execve, we could
// receive the notification for the death of the pre-execve task_t,
// this could also happen *before* we are notified that our task_t has
// changed.
if dbp.os.task != task {
continue
}
if !dbp.os.initialized {
if pidtask := C.get_task_for_pid(C.int(dbp.pid)); pidtask != 0 && dbp.os.task != pidtask {
continue
}
}
_, status, err := dbp.wait(dbp.pid, 0)
if err != nil {
return nil, err
}
dbp.postExit()
return nil, proc.ErrProcessExited{Pid: dbp.pid, Status: status.ExitStatus()}
case C.MACH_RCV_INTERRUPTED:
dbp.stopMu.Lock()
halt := dbp.os.halt
dbp.stopMu.Unlock()
if !halt {
// Call trapWait again, it seems
// MACH_RCV_INTERRUPTED is emitted before
// process natural death _sometimes_.
continue
}
return nil, nil
case 0:
return nil, fmt.Errorf("error while waiting for task")
}
// In macOS 10.12.1 if we received a notification for a task other than
// the inferior's task and the inferior's task is no longer valid, this
// means inferior called execve and its task_t changed.
if dbp.os.task != task && C.task_is_valid(dbp.os.task) == 0 {
dbp.os.task = task
kret := C.reset_exception_ports(dbp.os.task, &dbp.os.exceptionPort, &dbp.os.notificationPort)
if kret != C.KERN_SUCCESS {
return nil, fmt.Errorf("could not follow task across exec: %d\n", kret)
}
}
// Since we cannot be notified of new threads on OS X
// this is as good a time as any to check for them.
dbp.updateThreadList()
th, ok := dbp.threads[int(port)]
if !ok {
dbp.stopMu.Lock()
halt := dbp.os.halt
dbp.stopMu.Unlock()
if halt {
dbp.os.halt = false
return th, nil
}
if dbp.firstStart || th.singleStepping {
dbp.firstStart = false
return th, nil
}
if err := th.Continue(); err != nil {
return nil, err
}
continue
}
return th, nil
}
}
func (dbp *Process) waitForStop() ([]int, error) {
ports := make([]int, 0, len(dbp.threads))
count := 0
for {
var task C.task_t
port := C.mach_port_wait(dbp.os.portSet, &task, C.int(1))
if port != 0 && port != dbp.os.notificationPort && port != C.MACH_RCV_INTERRUPTED {
count = 0
ports = append(ports, int(port))
} else {
n := C.num_running_threads(dbp.os.task)
if n == 0 {
return ports, nil
} else if n < 0 {
return nil, fmt.Errorf("error waiting for thread stop %d", n)
} else if count > 16 {
return nil, fmt.Errorf("could not stop process %d", n)
}
}
}
}
func (dbp *Process) wait(pid, options int) (int, *sys.WaitStatus, error) {
var status sys.WaitStatus
wpid, err := sys.Wait4(pid, &status, options, nil)
return wpid, &status, err
}
func killProcess(pid int) error {
return sys.Kill(pid, sys.SIGINT)
}
func (dbp *Process) exitGuard(err error) error {
if err != ErrContinueThread {
return err
}
_, status, werr := dbp.wait(dbp.pid, sys.WNOHANG)
if werr == nil && status.Exited() {
dbp.postExit()
return proc.ErrProcessExited{Pid: dbp.pid, Status: status.ExitStatus()}
}
return err
}
func (dbp *Process) resume() error {
// all threads stopped over a breakpoint are made to step over it
for _, thread := range dbp.threads {
if thread.CurrentBreakpoint.Breakpoint != nil {
if err := thread.StepInstruction(); err != nil {
return err
}
thread.CurrentBreakpoint.Clear()
}
}
// everything is resumed
for _, thread := range dbp.threads {
if err := thread.resume(); err != nil {
return dbp.exitGuard(err)
}
}
return nil
}
// stop stops all running threads and sets breakpoints
func (dbp *Process) stop(trapthread *Thread) (err error) {
if dbp.exited {
return &proc.ErrProcessExited{Pid: dbp.Pid()}
}
for _, th := range dbp.threads {
if !th.Stopped() {
if err := th.stop(); err != nil {
return dbp.exitGuard(err)
}
}
}
ports, err := dbp.waitForStop()
if err != nil {
return err
}
if !dbp.os.initialized {
return nil
}
trapthread.SetCurrentBreakpoint()
for _, port := range ports {
if th, ok := dbp.threads[port]; ok {
err := th.SetCurrentBreakpoint()
if err != nil {
return err
}
}
}
return nil
}
func (dbp *Process) detach(kill bool) error {
return PtraceDetach(dbp.pid, 0)
}
func (dbp *Process) EntryPoint() (uint64, error) {
//TODO(aarzilli): implement this
return 0, nil
}
func initialize(dbp *Process) error { return nil }

View File

@ -0,0 +1,56 @@
//+build darwin,macnative
#include <sys/types.h>
#include <libproc.h>
#include <mach/mach.h>
#include <mach/mach_vm.h>
#include "mach_exc.h"
#include "exc.h"
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
boolean_t exc_server(
mach_msg_header_t *InHeadP,
mach_msg_header_t *OutHeadP);
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
boolean_t mach_exc_server(
mach_msg_header_t *InHeadP,
mach_msg_header_t *OutHeadP);
kern_return_t
acquire_mach_task(int, task_t*, mach_port_t*, mach_port_t*, mach_port_t*);
char *
find_executable(int pid);
kern_return_t
get_threads(task_t task, void *data,int limit);
int
thread_count(task_t task);
mach_port_t
mach_port_wait(mach_port_t, task_t*, int);
kern_return_t
mach_send_reply(mach_msg_header_t);
kern_return_t
raise_exception(mach_port_t, mach_port_t, mach_port_t, exception_type_t);
kern_return_t
reset_exception_ports(task_t task, mach_port_t *exception_port, mach_port_t *notification_port);
task_t
get_task_for_pid(int pid);
int
task_is_valid(task_t task);

View File

@ -0,0 +1,505 @@
package native
import (
"bytes"
"errors"
"fmt"
"io/ioutil"
"os"
"os/exec"
"os/signal"
"path/filepath"
"regexp"
"strconv"
"strings"
"syscall"
"time"
sys "golang.org/x/sys/unix"
"github.com/go-delve/delve/pkg/proc"
"github.com/go-delve/delve/pkg/proc/linutil"
isatty "github.com/mattn/go-isatty"
)
// Process statuses
const (
StatusSleeping = 'S'
StatusRunning = 'R'
StatusTraceStop = 't'
StatusZombie = 'Z'
// Kernel 2.6 has TraceStop as T
// TODO(derekparker) Since this means something different based on the
// version of the kernel ('T' is job control stop on modern 3.x+ kernels) we
// may want to differentiate at some point.
StatusTraceStopT = 'T'
)
// OSProcessDetails contains Linux specific
// process details.
type OSProcessDetails struct {
comm string
}
// Launch creates and begins debugging a new process. First entry in
// `cmd` is the program to run, and then rest are the arguments
// to be supplied to that process. `wd` is working directory of the program.
// If the DWARF information cannot be found in the binary, Delve will look
// for external debug files in the directories passed in.
func Launch(cmd []string, wd string, foreground bool, debugInfoDirs []string) (*Process, error) {
var (
process *exec.Cmd
err error
)
// check that the argument to Launch is an executable file
if fi, staterr := os.Stat(cmd[0]); staterr == nil && (fi.Mode()&0111) == 0 {
return nil, proc.ErrNotExecutable
}
if !isatty.IsTerminal(os.Stdin.Fd()) {
// exec.(*Process).Start will fail if we try to send a process to
// foreground but we are not attached to a terminal.
foreground = false
}
dbp := New(0)
dbp.common = proc.NewCommonProcess(true)
dbp.execPtraceFunc(func() {
process = exec.Command(cmd[0])
process.Args = cmd
process.Stdout = os.Stdout
process.Stderr = os.Stderr
process.SysProcAttr = &syscall.SysProcAttr{Ptrace: true, Setpgid: true, Foreground: foreground}
if foreground {
signal.Ignore(syscall.SIGTTOU, syscall.SIGTTIN)
process.Stdin = os.Stdin
}
if wd != "" {
process.Dir = wd
}
err = process.Start()
})
if err != nil {
return nil, err
}
dbp.pid = process.Process.Pid
dbp.childProcess = true
_, _, err = dbp.wait(process.Process.Pid, 0)
if err != nil {
return nil, fmt.Errorf("waiting for target execve failed: %s", err)
}
if err = dbp.initialize(cmd[0], debugInfoDirs); err != nil {
return nil, err
}
return dbp, nil
}
// Attach to an existing process with the given PID. Once attached, if
// the DWARF information cannot be found in the binary, Delve will look
// for external debug files in the directories passed in.
func Attach(pid int, debugInfoDirs []string) (*Process, error) {
dbp := New(pid)
dbp.common = proc.NewCommonProcess(true)
var err error
dbp.execPtraceFunc(func() { err = PtraceAttach(dbp.pid) })
if err != nil {
return nil, err
}
_, _, err = dbp.wait(dbp.pid, 0)
if err != nil {
return nil, err
}
err = dbp.initialize(findExecutable("", dbp.pid), debugInfoDirs)
if err != nil {
dbp.Detach(false)
return nil, err
}
return dbp, nil
}
func initialize(dbp *Process) error {
comm, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/comm", dbp.pid))
if err == nil {
// removes newline character
comm = bytes.TrimSuffix(comm, []byte("\n"))
}
if comm == nil || len(comm) <= 0 {
stat, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/stat", dbp.pid))
if err != nil {
return fmt.Errorf("could not read proc stat: %v", err)
}
expr := fmt.Sprintf("%d\\s*\\((.*)\\)", dbp.pid)
rexp, err := regexp.Compile(expr)
if err != nil {
return fmt.Errorf("regexp compile error: %v", err)
}
match := rexp.FindSubmatch(stat)
if match == nil {
return fmt.Errorf("no match found using regexp '%s' in /proc/%d/stat", expr, dbp.pid)
}
comm = match[1]
}
dbp.os.comm = strings.Replace(string(comm), "%", "%%", -1)
return nil
}
// kill kills the target process.
func (dbp *Process) kill() (err error) {
if dbp.exited {
return nil
}
if !dbp.threads[dbp.pid].Stopped() {
return errors.New("process must be stopped in order to kill it")
}
if err = sys.Kill(-dbp.pid, sys.SIGKILL); err != nil {
return errors.New("could not deliver signal " + err.Error())
}
if _, _, err = dbp.wait(dbp.pid, 0); err != nil {
return
}
dbp.postExit()
return
}
func (dbp *Process) requestManualStop() (err error) {
return sys.Kill(dbp.pid, sys.SIGTRAP)
}
// Attach to a newly created thread, and store that thread in our list of
// known threads.
func (dbp *Process) addThread(tid int, attach bool) (*Thread, error) {
if thread, ok := dbp.threads[tid]; ok {
return thread, nil
}
var err error
if attach {
dbp.execPtraceFunc(func() { err = sys.PtraceAttach(tid) })
if err != nil && err != sys.EPERM {
// Do not return err if err == EPERM,
// we may already be tracing this thread due to
// PTRACE_O_TRACECLONE. We will surely blow up later
// if we truly don't have permissions.
return nil, fmt.Errorf("could not attach to new thread %d %s", tid, err)
}
pid, status, err := dbp.waitFast(tid)
if err != nil {
return nil, err
}
if status.Exited() {
return nil, fmt.Errorf("thread already exited %d", pid)
}
}
dbp.execPtraceFunc(func() { err = syscall.PtraceSetOptions(tid, syscall.PTRACE_O_TRACECLONE) })
if err == syscall.ESRCH {
if _, _, err = dbp.waitFast(tid); err != nil {
return nil, fmt.Errorf("error while waiting after adding thread: %d %s", tid, err)
}
dbp.execPtraceFunc(func() { err = syscall.PtraceSetOptions(tid, syscall.PTRACE_O_TRACECLONE) })
if err == syscall.ESRCH {
return nil, err
}
if err != nil {
return nil, fmt.Errorf("could not set options for new traced thread %d %s", tid, err)
}
}
dbp.threads[tid] = &Thread{
ID: tid,
dbp: dbp,
os: new(OSSpecificDetails),
}
if dbp.currentThread == nil {
dbp.SwitchThread(tid)
}
return dbp.threads[tid], nil
}
func (dbp *Process) updateThreadList() error {
tids, _ := filepath.Glob(fmt.Sprintf("/proc/%d/task/*", dbp.pid))
for _, tidpath := range tids {
tidstr := filepath.Base(tidpath)
tid, err := strconv.Atoi(tidstr)
if err != nil {
return err
}
if _, err := dbp.addThread(tid, tid != dbp.pid); err != nil {
return err
}
}
return linutil.ElfUpdateSharedObjects(dbp)
}
func findExecutable(path string, pid int) string {
if path == "" {
path = fmt.Sprintf("/proc/%d/exe", pid)
}
return path
}
func (dbp *Process) trapWait(pid int) (*Thread, error) {
return dbp.trapWaitInternal(pid, false)
}
func (dbp *Process) trapWaitInternal(pid int, halt bool) (*Thread, error) {
for {
wpid, status, err := dbp.wait(pid, 0)
if err != nil {
return nil, fmt.Errorf("wait err %s %d", err, pid)
}
if wpid == 0 {
continue
}
th, ok := dbp.threads[wpid]
if ok {
th.Status = (*WaitStatus)(status)
}
if status.Exited() {
if wpid == dbp.pid {
dbp.postExit()
return nil, proc.ErrProcessExited{Pid: wpid, Status: status.ExitStatus()}
}
delete(dbp.threads, wpid)
continue
}
if status.StopSignal() == sys.SIGTRAP && status.TrapCause() == sys.PTRACE_EVENT_CLONE {
// A traced thread has cloned a new thread, grab the pid and
// add it to our list of traced threads.
var cloned uint
dbp.execPtraceFunc(func() { cloned, err = sys.PtraceGetEventMsg(wpid) })
if err != nil {
if err == sys.ESRCH {
// thread died while we were adding it
continue
}
return nil, fmt.Errorf("could not get event message: %s", err)
}
th, err = dbp.addThread(int(cloned), false)
if err != nil {
if err == sys.ESRCH {
// thread died while we were adding it
delete(dbp.threads, int(cloned))
continue
}
return nil, err
}
if halt {
th.os.running = false
dbp.threads[int(wpid)].os.running = false
return nil, nil
}
if err = th.Continue(); err != nil {
if err == sys.ESRCH {
// thread died while we were adding it
delete(dbp.threads, th.ID)
continue
}
return nil, fmt.Errorf("could not continue new thread %d %s", cloned, err)
}
if err = dbp.threads[int(wpid)].Continue(); err != nil {
if err != sys.ESRCH {
return nil, fmt.Errorf("could not continue existing thread %d %s", wpid, err)
}
}
continue
}
if th == nil {
// Sometimes we get an unknown thread, ignore it?
continue
}
if (halt && status.StopSignal() == sys.SIGSTOP) || (status.StopSignal() == sys.SIGTRAP) {
th.os.running = false
return th, nil
}
if th != nil {
// TODO(dp) alert user about unexpected signals here.
if err := th.resumeWithSig(int(status.StopSignal())); err != nil {
if err == sys.ESRCH {
return nil, proc.ErrProcessExited{Pid: dbp.pid}
}
return nil, err
}
}
}
}
func (dbp *Process) loadProcessInformation() {
}
func status(pid int, comm string) rune {
f, err := os.Open(fmt.Sprintf("/proc/%d/stat", pid))
if err != nil {
return '\000'
}
defer f.Close()
var (
p int
state rune
)
// The second field of /proc/pid/stat is the name of the task in parenthesis.
// The name of the task is the base name of the executable for this process limited to TASK_COMM_LEN characters
// Since both parenthesis and spaces can appear inside the name of the task and no escaping happens we need to read the name of the executable first
// See: include/linux/sched.c:315 and include/linux/sched.c:1510
fmt.Fscanf(f, "%d ("+comm+") %c", &p, &state)
return state
}
// waitFast is like wait but does not handle process-exit correctly
func (dbp *Process) waitFast(pid int) (int, *sys.WaitStatus, error) {
var s sys.WaitStatus
wpid, err := sys.Wait4(pid, &s, sys.WALL, nil)
return wpid, &s, err
}
func (dbp *Process) wait(pid, options int) (int, *sys.WaitStatus, error) {
var s sys.WaitStatus
if (pid != dbp.pid) || (options != 0) {
wpid, err := sys.Wait4(pid, &s, sys.WALL|options, nil)
return wpid, &s, err
}
// If we call wait4/waitpid on a thread that is the leader of its group,
// with options == 0, while ptracing and the thread leader has exited leaving
// zombies of its own then waitpid hangs forever this is apparently intended
// behaviour in the linux kernel because it's just so convenient.
// Therefore we call wait4 in a loop with WNOHANG, sleeping a while between
// calls and exiting when either wait4 succeeds or we find out that the thread
// has become a zombie.
// References:
// https://sourceware.org/bugzilla/show_bug.cgi?id=12702
// https://sourceware.org/bugzilla/show_bug.cgi?id=10095
// https://sourceware.org/bugzilla/attachment.cgi?id=5685
for {
wpid, err := sys.Wait4(pid, &s, sys.WNOHANG|sys.WALL|options, nil)
if err != nil {
return 0, nil, err
}
if wpid != 0 {
return wpid, &s, err
}
if status(pid, dbp.os.comm) == StatusZombie {
return pid, nil, nil
}
time.Sleep(200 * time.Millisecond)
}
}
func (dbp *Process) exitGuard(err error) error {
if err != sys.ESRCH {
return err
}
if status(dbp.pid, dbp.os.comm) == StatusZombie {
_, err := dbp.trapWaitInternal(-1, false)
return err
}
return err
}
func (dbp *Process) resume() error {
// all threads stopped over a breakpoint are made to step over it
for _, thread := range dbp.threads {
if thread.CurrentBreakpoint.Breakpoint != nil {
if err := thread.StepInstruction(); err != nil {
return err
}
thread.CurrentBreakpoint.Clear()
}
}
// everything is resumed
for _, thread := range dbp.threads {
if err := thread.resume(); err != nil && err != sys.ESRCH {
return err
}
}
return nil
}
// stop stops all running threads threads and sets breakpoints
func (dbp *Process) stop(trapthread *Thread) (err error) {
if dbp.exited {
return &proc.ErrProcessExited{Pid: dbp.Pid()}
}
for _, th := range dbp.threads {
if !th.Stopped() {
if err := th.stop(); err != nil {
return dbp.exitGuard(err)
}
}
}
// wait for all threads to stop
for {
allstopped := true
for _, th := range dbp.threads {
if th.os.running {
allstopped = false
break
}
}
if allstopped {
break
}
_, err := dbp.trapWaitInternal(-1, true)
if err != nil {
return err
}
}
if err := linutil.ElfUpdateSharedObjects(dbp); err != nil {
return err
}
// set breakpoints on all threads
for _, th := range dbp.threads {
if th.CurrentBreakpoint.Breakpoint == nil {
if err := th.SetCurrentBreakpoint(); err != nil {
return err
}
}
}
return nil
}
func (dbp *Process) detach(kill bool) error {
for threadID := range dbp.threads {
err := PtraceDetach(threadID, 0)
if err != nil {
return err
}
}
if kill {
return nil
}
// For some reason the process will sometimes enter stopped state after a
// detach, this doesn't happen immediately either.
// We have to wait a bit here, then check if the main thread is stopped and
// SIGCONT it if it is.
time.Sleep(50 * time.Millisecond)
if s := status(dbp.pid, dbp.os.comm); s == 'T' {
sys.Kill(dbp.pid, sys.SIGCONT)
}
return nil
}
// EntryPoint will return the process entry point address, useful for
// debugging PIEs.
func (dbp *Process) EntryPoint() (uint64, error) {
auxvbuf, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/auxv", dbp.pid))
if err != nil {
return 0, fmt.Errorf("could not read auxiliary vector: %v", err)
}
return linutil.EntryPointFromAuxvAMD64(auxvbuf), nil
}
func killProcess(pid int) error {
return sys.Kill(pid, sys.SIGINT)
}

View File

@ -0,0 +1,495 @@
package native
import (
"debug/pe"
"fmt"
"io"
"os"
"os/exec"
"path/filepath"
"syscall"
"unsafe"
sys "golang.org/x/sys/windows"
"github.com/go-delve/delve/pkg/proc"
)
// OSProcessDetails holds Windows specific information.
type OSProcessDetails struct {
hProcess syscall.Handle
breakThread int
entryPoint uint64
}
func openExecutablePathPE(path string) (*pe.File, io.Closer, error) {
f, err := os.OpenFile(path, 0, os.ModePerm)
if err != nil {
return nil, nil, err
}
peFile, err := pe.NewFile(f)
if err != nil {
f.Close()
return nil, nil, err
}
return peFile, f, nil
}
// Launch creates and begins debugging a new process.
func Launch(cmd []string, wd string, foreground bool, _ []string) (*Process, error) {
argv0Go, err := filepath.Abs(cmd[0])
if err != nil {
return nil, err
}
// Make sure the binary exists and is an executable file
if filepath.Base(cmd[0]) == cmd[0] {
if _, err := exec.LookPath(cmd[0]); err != nil {
return nil, err
}
}
_, closer, err := openExecutablePathPE(argv0Go)
if err != nil {
return nil, proc.ErrNotExecutable
}
closer.Close()
var p *os.Process
dbp := New(0)
dbp.common = proc.NewCommonProcess(true)
dbp.execPtraceFunc(func() {
attr := &os.ProcAttr{
Dir: wd,
Files: []*os.File{os.Stdin, os.Stdout, os.Stderr},
Sys: &syscall.SysProcAttr{
CreationFlags: _DEBUG_ONLY_THIS_PROCESS,
},
}
p, err = os.StartProcess(argv0Go, cmd, attr)
})
if err != nil {
return nil, err
}
defer p.Release()
dbp.pid = p.Pid
dbp.childProcess = true
if err = dbp.initialize(argv0Go, []string{}); err != nil {
dbp.Detach(true)
return nil, err
}
return dbp, nil
}
func initialize(dbp *Process) error {
// It should not actually be possible for the
// call to waitForDebugEvent to fail, since Windows
// will always fire a CREATE_PROCESS_DEBUG_EVENT event
// immediately after launching under DEBUG_ONLY_THIS_PROCESS.
// Attaching with DebugActiveProcess has similar effect.
var err error
var tid, exitCode int
dbp.execPtraceFunc(func() {
tid, exitCode, err = dbp.waitForDebugEvent(waitBlocking)
})
if err != nil {
return err
}
if tid == 0 {
dbp.postExit()
return proc.ErrProcessExited{Pid: dbp.pid, Status: exitCode}
}
// Suspend all threads so that the call to _ContinueDebugEvent will
// not resume the target.
for _, thread := range dbp.threads {
_, err := _SuspendThread(thread.os.hThread)
if err != nil {
return err
}
}
dbp.execPtraceFunc(func() {
err = _ContinueDebugEvent(uint32(dbp.pid), uint32(dbp.os.breakThread), _DBG_CONTINUE)
})
return err
}
// findExePath searches for process pid, and returns its executable path.
func findExePath(pid int) (string, error) {
// Original code suggested different approach (see below).
// Maybe it could be useful in the future.
//
// Find executable path from PID/handle on Windows:
// https://msdn.microsoft.com/en-us/library/aa366789(VS.85).aspx
p, err := syscall.OpenProcess(syscall.PROCESS_QUERY_INFORMATION, false, uint32(pid))
if err != nil {
return "", err
}
defer syscall.CloseHandle(p)
n := uint32(128)
for {
buf := make([]uint16, int(n))
err = _QueryFullProcessImageName(p, 0, &buf[0], &n)
switch err {
case syscall.ERROR_INSUFFICIENT_BUFFER:
// try bigger buffer
n *= 2
// but stop if it gets too big
if n > 10000 {
return "", err
}
case nil:
return syscall.UTF16ToString(buf[:n]), nil
default:
return "", err
}
}
}
// Attach to an existing process with the given PID.
func Attach(pid int, _ []string) (*Process, error) {
// TODO: Probably should have SeDebugPrivilege before starting here.
err := _DebugActiveProcess(uint32(pid))
if err != nil {
return nil, err
}
exepath, err := findExePath(pid)
if err != nil {
return nil, err
}
dbp := New(pid)
if err = dbp.initialize(exepath, []string{}); err != nil {
dbp.Detach(true)
return nil, err
}
return dbp, nil
}
// kill kills the process.
func (dbp *Process) kill() error {
if dbp.exited {
return nil
}
p, err := os.FindProcess(dbp.pid)
if err != nil {
return err
}
defer p.Release()
// TODO: Should not have to ignore failures here,
// but some tests appear to Kill twice causing
// this to fail on second attempt.
_ = syscall.TerminateProcess(dbp.os.hProcess, 1)
dbp.execPtraceFunc(func() {
dbp.waitForDebugEvent(waitBlocking | waitDontHandleExceptions)
})
p.Wait()
dbp.postExit()
return nil
}
func (dbp *Process) requestManualStop() error {
return _DebugBreakProcess(dbp.os.hProcess)
}
func (dbp *Process) updateThreadList() error {
// We ignore this request since threads are being
// tracked as they are created/killed in waitForDebugEvent.
return nil
}
func (dbp *Process) addThread(hThread syscall.Handle, threadID int, attach, suspendNewThreads bool) (*Thread, error) {
if thread, ok := dbp.threads[threadID]; ok {
return thread, nil
}
thread := &Thread{
ID: threadID,
dbp: dbp,
os: new(OSSpecificDetails),
}
thread.os.hThread = hThread
dbp.threads[threadID] = thread
if dbp.currentThread == nil {
dbp.SwitchThread(thread.ID)
}
if suspendNewThreads {
_, err := _SuspendThread(thread.os.hThread)
if err != nil {
return nil, err
}
}
return thread, nil
}
func findExecutable(path string, pid int) string {
return path
}
type waitForDebugEventFlags int
const (
waitBlocking waitForDebugEventFlags = 1 << iota
waitSuspendNewThreads
waitDontHandleExceptions
)
const _MS_VC_EXCEPTION = 0x406D1388 // part of VisualC protocol to set thread names
func (dbp *Process) waitForDebugEvent(flags waitForDebugEventFlags) (threadID, exitCode int, err error) {
var debugEvent _DEBUG_EVENT
shouldExit := false
for {
continueStatus := uint32(_DBG_CONTINUE)
var milliseconds uint32 = 0
if flags&waitBlocking != 0 {
milliseconds = syscall.INFINITE
}
// Wait for a debug event...
err := _WaitForDebugEvent(&debugEvent, milliseconds)
if err != nil {
return 0, 0, err
}
// ... handle each event kind ...
unionPtr := unsafe.Pointer(&debugEvent.U[0])
switch debugEvent.DebugEventCode {
case _CREATE_PROCESS_DEBUG_EVENT:
debugInfo := (*_CREATE_PROCESS_DEBUG_INFO)(unionPtr)
hFile := debugInfo.File
if hFile != 0 && hFile != syscall.InvalidHandle {
err = syscall.CloseHandle(hFile)
if err != nil {
return 0, 0, err
}
}
dbp.os.entryPoint = uint64(debugInfo.BaseOfImage)
dbp.os.hProcess = debugInfo.Process
_, err = dbp.addThread(debugInfo.Thread, int(debugEvent.ThreadId), false, flags&waitSuspendNewThreads != 0)
if err != nil {
return 0, 0, err
}
break
case _CREATE_THREAD_DEBUG_EVENT:
debugInfo := (*_CREATE_THREAD_DEBUG_INFO)(unionPtr)
_, err = dbp.addThread(debugInfo.Thread, int(debugEvent.ThreadId), false, flags&waitSuspendNewThreads != 0)
if err != nil {
return 0, 0, err
}
break
case _EXIT_THREAD_DEBUG_EVENT:
delete(dbp.threads, int(debugEvent.ThreadId))
break
case _OUTPUT_DEBUG_STRING_EVENT:
//TODO: Handle debug output strings
break
case _LOAD_DLL_DEBUG_EVENT:
debugInfo := (*_LOAD_DLL_DEBUG_INFO)(unionPtr)
hFile := debugInfo.File
if hFile != 0 && hFile != syscall.InvalidHandle {
err = syscall.CloseHandle(hFile)
if err != nil {
return 0, 0, err
}
}
break
case _UNLOAD_DLL_DEBUG_EVENT:
break
case _RIP_EVENT:
break
case _EXCEPTION_DEBUG_EVENT:
if flags&waitDontHandleExceptions != 0 {
continueStatus = _DBG_EXCEPTION_NOT_HANDLED
break
}
exception := (*_EXCEPTION_DEBUG_INFO)(unionPtr)
tid := int(debugEvent.ThreadId)
switch code := exception.ExceptionRecord.ExceptionCode; code {
case _EXCEPTION_BREAKPOINT:
// check if the exception address really is a breakpoint instruction, if
// it isn't we already removed that breakpoint and we can't deal with
// this exception anymore.
atbp := true
if thread, found := dbp.threads[tid]; found {
data := make([]byte, dbp.bi.Arch.BreakpointSize())
if _, err := thread.ReadMemory(data, exception.ExceptionRecord.ExceptionAddress); err == nil {
instr := dbp.bi.Arch.BreakpointInstruction()
for i := range instr {
if data[i] != instr[i] {
atbp = false
break
}
}
}
if !atbp {
thread.SetPC(uint64(exception.ExceptionRecord.ExceptionAddress))
}
}
if atbp {
dbp.os.breakThread = tid
return tid, 0, nil
} else {
continueStatus = _DBG_CONTINUE
}
case _EXCEPTION_SINGLE_STEP:
dbp.os.breakThread = tid
return tid, 0, nil
case _MS_VC_EXCEPTION:
// This exception is sent to set the thread name in VisualC, we should
// mask it or it might crash the program.
continueStatus = _DBG_CONTINUE
default:
continueStatus = _DBG_EXCEPTION_NOT_HANDLED
}
case _EXIT_PROCESS_DEBUG_EVENT:
debugInfo := (*_EXIT_PROCESS_DEBUG_INFO)(unionPtr)
exitCode = int(debugInfo.ExitCode)
shouldExit = true
default:
return 0, 0, fmt.Errorf("unknown debug event code: %d", debugEvent.DebugEventCode)
}
// .. and then continue unless we received an event that indicated we should break into debugger.
err = _ContinueDebugEvent(debugEvent.ProcessId, debugEvent.ThreadId, continueStatus)
if err != nil {
return 0, 0, err
}
if shouldExit {
return 0, exitCode, nil
}
}
}
func (dbp *Process) trapWait(pid int) (*Thread, error) {
var err error
var tid, exitCode int
dbp.execPtraceFunc(func() {
tid, exitCode, err = dbp.waitForDebugEvent(waitBlocking)
})
if err != nil {
return nil, err
}
if tid == 0 {
dbp.postExit()
return nil, proc.ErrProcessExited{Pid: dbp.pid, Status: exitCode}
}
th := dbp.threads[tid]
return th, nil
}
func (dbp *Process) wait(pid, options int) (int, *sys.WaitStatus, error) {
return 0, nil, fmt.Errorf("not implemented: wait")
}
func (dbp *Process) exitGuard(err error) error {
return err
}
func (dbp *Process) resume() error {
for _, thread := range dbp.threads {
if thread.CurrentBreakpoint.Breakpoint != nil {
if err := thread.StepInstruction(); err != nil {
return err
}
thread.CurrentBreakpoint.Clear()
}
}
for _, thread := range dbp.threads {
_, err := _ResumeThread(thread.os.hThread)
if err != nil {
return err
}
}
return nil
}
// stop stops all running threads threads and sets breakpoints
func (dbp *Process) stop(trapthread *Thread) (err error) {
if dbp.exited {
return &proc.ErrProcessExited{Pid: dbp.Pid()}
}
// While the debug event that stopped the target was being propagated
// other target threads could generate other debug events.
// After this function we need to know about all the threads
// stopped on a breakpoint. To do that we first suspend all target
// threads and then repeatedly call _ContinueDebugEvent followed by
// waitForDebugEvent in non-blocking mode.
// We need to explicitly call SuspendThread because otherwise the
// call to _ContinueDebugEvent will resume execution of some of the
// target threads.
err = trapthread.SetCurrentBreakpoint()
if err != nil {
return err
}
for _, thread := range dbp.threads {
_, err := _SuspendThread(thread.os.hThread)
if err != nil {
return err
}
}
for {
var err error
var tid int
dbp.execPtraceFunc(func() {
err = _ContinueDebugEvent(uint32(dbp.pid), uint32(dbp.os.breakThread), _DBG_CONTINUE)
if err == nil {
tid, _, _ = dbp.waitForDebugEvent(waitSuspendNewThreads)
}
})
if err != nil {
return err
}
if tid == 0 {
break
}
err = dbp.threads[tid].SetCurrentBreakpoint()
if err != nil {
return err
}
}
return nil
}
func (dbp *Process) detach(kill bool) error {
if !kill {
for _, thread := range dbp.threads {
_, err := _ResumeThread(thread.os.hThread)
if err != nil {
return err
}
}
}
return _DebugActiveProcessStop(uint32(dbp.pid))
}
func (dbp *Process) EntryPoint() (uint64, error) {
return dbp.os.entryPoint, nil
}
func killProcess(pid int) error {
p, err := os.FindProcess(pid)
if err != nil {
return err
}
defer p.Release()
return p.Kill()
}

View File

@ -0,0 +1,30 @@
//+build darwin,macnative
package native
import sys "golang.org/x/sys/unix"
// PtraceAttach executes the sys.PtraceAttach call.
func PtraceAttach(pid int) error {
return sys.PtraceAttach(pid)
}
// PtraceDetach executes the PT_DETACH ptrace call.
func PtraceDetach(tid, sig int) error {
return ptrace(sys.PT_DETACH, tid, 1, uintptr(sig))
}
// PtraceCont executes the PTRACE_CONT ptrace call.
func PtraceCont(tid, sig int) error {
return ptrace(sys.PTRACE_CONT, tid, 1, 0)
}
// PtraceSingleStep returns PT_STEP ptrace call.
func PtraceSingleStep(tid int) error {
return ptrace(sys.PT_STEP, tid, 1, 0)
}
func ptrace(request, pid int, addr uintptr, data uintptr) (err error) {
_, _, err = sys.Syscall6(sys.SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
return
}

View File

@ -0,0 +1,84 @@
package native
import (
"syscall"
"unsafe"
sys "golang.org/x/sys/unix"
"github.com/go-delve/delve/pkg/proc/linutil"
)
// PtraceAttach executes the sys.PtraceAttach call.
func PtraceAttach(pid int) error {
return sys.PtraceAttach(pid)
}
// PtraceDetach calls ptrace(PTRACE_DETACH).
func PtraceDetach(tid, sig int) error {
_, _, err := sys.Syscall6(sys.SYS_PTRACE, sys.PTRACE_DETACH, uintptr(tid), 1, uintptr(sig), 0, 0)
if err != syscall.Errno(0) {
return err
}
return nil
}
// PtraceCont executes ptrace PTRACE_CONT
func PtraceCont(tid, sig int) error {
return sys.PtraceCont(tid, sig)
}
// PtraceSingleStep executes ptrace PTRACE_SINGLE_STEP.
func PtraceSingleStep(tid int) error {
return sys.PtraceSingleStep(tid)
}
// PtracePokeUser execute ptrace PTRACE_POKE_USER.
func PtracePokeUser(tid int, off, addr uintptr) error {
_, _, err := sys.Syscall6(sys.SYS_PTRACE, sys.PTRACE_POKEUSR, uintptr(tid), uintptr(off), uintptr(addr), 0, 0)
if err != syscall.Errno(0) {
return err
}
return nil
}
// PtracePeekUser execute ptrace PTRACE_PEEK_USER.
func PtracePeekUser(tid int, off uintptr) (uintptr, error) {
var val uintptr
_, _, err := syscall.Syscall6(syscall.SYS_PTRACE, syscall.PTRACE_PEEKUSR, uintptr(tid), uintptr(off), uintptr(unsafe.Pointer(&val)), 0, 0)
if err != syscall.Errno(0) {
return 0, err
}
return val, nil
}
// PtraceGetRegset returns floating point registers of the specified thread
// using PTRACE.
// See amd64_linux_fetch_inferior_registers in gdb/amd64-linux-nat.c.html
// and amd64_supply_xsave in gdb/amd64-tdep.c.html
// and Section 13.1 (and following) of Intel® 64 and IA-32 Architectures Software Developers Manual, Volume 1: Basic Architecture
func PtraceGetRegset(tid int) (regset linutil.AMD64Xstate, err error) {
_, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_GETFPREGS, uintptr(tid), uintptr(0), uintptr(unsafe.Pointer(&regset.AMD64PtraceFpRegs)), 0, 0)
if err == syscall.Errno(0) || err == syscall.ENODEV {
// ignore ENODEV, it just means this CPU doesn't have X87 registers (??)
err = nil
}
var xstateargs [_X86_XSTATE_MAX_SIZE]byte
iov := sys.Iovec{Base: &xstateargs[0], Len: _X86_XSTATE_MAX_SIZE}
_, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_GETREGSET, uintptr(tid), _NT_X86_XSTATE, uintptr(unsafe.Pointer(&iov)), 0, 0)
if err != syscall.Errno(0) {
if err == syscall.ENODEV || err == syscall.EIO {
// ignore ENODEV, it just means this CPU or kernel doesn't support XSTATE, see https://github.com/go-delve/delve/issues/1022
// also ignore EIO, it means that we are running on an old kernel (pre 2.6.34) and PTRACE_GETREGSET is not implemented
err = nil
}
return
} else {
err = nil
}
regset.Xsave = xstateargs[:iov.Len]
err = linutil.AMD64XstateRead(regset.Xsave, false, &regset)
return regset, err
}

View File

@ -0,0 +1,377 @@
//+build darwin,macnative
package native
// #include "threads_darwin.h"
import "C"
import (
"encoding/binary"
"errors"
"fmt"
"unsafe"
"golang.org/x/arch/x86/x86asm"
"github.com/go-delve/delve/pkg/proc"
)
// Regs represents CPU registers on an AMD64 processor.
type Regs struct {
rax uint64
rbx uint64
rcx uint64
rdx uint64
rdi uint64
rsi uint64
rbp uint64
rsp uint64
r8 uint64
r9 uint64
r10 uint64
r11 uint64
r12 uint64
r13 uint64
r14 uint64
r15 uint64
rip uint64
rflags uint64
cs uint64
fs uint64
gs uint64
gsBase uint64
fpregs []proc.Register
}
func (r *Regs) Slice(floatingPoint bool) []proc.Register {
var regs = []struct {
k string
v uint64
}{
{"Rip", r.rip},
{"Rsp", r.rsp},
{"Rax", r.rax},
{"Rbx", r.rbx},
{"Rcx", r.rcx},
{"Rdx", r.rdx},
{"Rdi", r.rdi},
{"Rsi", r.rsi},
{"Rbp", r.rbp},
{"R8", r.r8},
{"R9", r.r9},
{"R10", r.r10},
{"R11", r.r11},
{"R12", r.r12},
{"R13", r.r13},
{"R14", r.r14},
{"R15", r.r15},
{"Rflags", r.rflags},
{"Cs", r.cs},
{"Fs", r.fs},
{"Gs", r.gs},
{"Gs_base", r.gsBase},
}
out := make([]proc.Register, 0, len(regs)+len(r.fpregs))
for _, reg := range regs {
if reg.k == "Rflags" {
out = proc.AppendEflagReg(out, reg.k, reg.v)
} else {
out = proc.AppendQwordReg(out, reg.k, reg.v)
}
}
if floatingPoint {
out = append(out, r.fpregs...)
}
return out
}
// PC returns the current program counter
// i.e. the RIP CPU register.
func (r *Regs) PC() uint64 {
return r.rip
}
// SP returns the stack pointer location,
// i.e. the RSP register.
func (r *Regs) SP() uint64 {
return r.rsp
}
func (r *Regs) BP() uint64 {
return r.rbp
}
// CX returns the value of the RCX register.
func (r *Regs) CX() uint64 {
return r.rcx
}
// TLS returns the value of the register
// that contains the location of the thread
// local storage segment.
func (r *Regs) TLS() uint64 {
return r.gsBase
}
func (r *Regs) GAddr() (uint64, bool) {
return 0, false
}
// SetPC sets the RIP register to the value specified by `pc`.
func (thread *Thread) SetPC(pc uint64) error {
kret := C.set_pc(thread.os.threadAct, C.uint64_t(pc))
if kret != C.KERN_SUCCESS {
return fmt.Errorf("could not set pc")
}
return nil
}
// SetSP sets the RSP register to the value specified by `pc`.
func (thread *Thread) SetSP(sp uint64) error {
return errors.New("not implemented")
}
func (thread *Thread) SetDX(dx uint64) error {
return errors.New("not implemented")
}
func (r *Regs) Get(n int) (uint64, error) {
reg := x86asm.Reg(n)
const (
mask8 = 0x000f
mask16 = 0x00ff
mask32 = 0xffff
)
switch reg {
// 8-bit
case x86asm.AL:
return r.rax & mask8, nil
case x86asm.CL:
return r.rcx & mask8, nil
case x86asm.DL:
return r.rdx & mask8, nil
case x86asm.BL:
return r.rbx & mask8, nil
case x86asm.AH:
return (r.rax >> 8) & mask8, nil
case x86asm.CH:
return (r.rcx >> 8) & mask8, nil
case x86asm.DH:
return (r.rdx >> 8) & mask8, nil
case x86asm.BH:
return (r.rbx >> 8) & mask8, nil
case x86asm.SPB:
return r.rsp & mask8, nil
case x86asm.BPB:
return r.rbp & mask8, nil
case x86asm.SIB:
return r.rsi & mask8, nil
case x86asm.DIB:
return r.rdi & mask8, nil
case x86asm.R8B:
return r.r8 & mask8, nil
case x86asm.R9B:
return r.r9 & mask8, nil
case x86asm.R10B:
return r.r10 & mask8, nil
case x86asm.R11B:
return r.r11 & mask8, nil
case x86asm.R12B:
return r.r12 & mask8, nil
case x86asm.R13B:
return r.r13 & mask8, nil
case x86asm.R14B:
return r.r14 & mask8, nil
case x86asm.R15B:
return r.r15 & mask8, nil
// 16-bit
case x86asm.AX:
return r.rax & mask16, nil
case x86asm.CX:
return r.rcx & mask16, nil
case x86asm.DX:
return r.rdx & mask16, nil
case x86asm.BX:
return r.rbx & mask16, nil
case x86asm.SP:
return r.rsp & mask16, nil
case x86asm.BP:
return r.rbp & mask16, nil
case x86asm.SI:
return r.rsi & mask16, nil
case x86asm.DI:
return r.rdi & mask16, nil
case x86asm.R8W:
return r.r8 & mask16, nil
case x86asm.R9W:
return r.r9 & mask16, nil
case x86asm.R10W:
return r.r10 & mask16, nil
case x86asm.R11W:
return r.r11 & mask16, nil
case x86asm.R12W:
return r.r12 & mask16, nil
case x86asm.R13W:
return r.r13 & mask16, nil
case x86asm.R14W:
return r.r14 & mask16, nil
case x86asm.R15W:
return r.r15 & mask16, nil
// 32-bit
case x86asm.EAX:
return r.rax & mask32, nil
case x86asm.ECX:
return r.rcx & mask32, nil
case x86asm.EDX:
return r.rdx & mask32, nil
case x86asm.EBX:
return r.rbx & mask32, nil
case x86asm.ESP:
return r.rsp & mask32, nil
case x86asm.EBP:
return r.rbp & mask32, nil
case x86asm.ESI:
return r.rsi & mask32, nil
case x86asm.EDI:
return r.rdi & mask32, nil
case x86asm.R8L:
return r.r8 & mask32, nil
case x86asm.R9L:
return r.r9 & mask32, nil
case x86asm.R10L:
return r.r10 & mask32, nil
case x86asm.R11L:
return r.r11 & mask32, nil
case x86asm.R12L:
return r.r12 & mask32, nil
case x86asm.R13L:
return r.r13 & mask32, nil
case x86asm.R14L:
return r.r14 & mask32, nil
case x86asm.R15L:
return r.r15 & mask32, nil
// 64-bit
case x86asm.RAX:
return r.rax, nil
case x86asm.RCX:
return r.rcx, nil
case x86asm.RDX:
return r.rdx, nil
case x86asm.RBX:
return r.rbx, nil
case x86asm.RSP:
return r.rsp, nil
case x86asm.RBP:
return r.rbp, nil
case x86asm.RSI:
return r.rsi, nil
case x86asm.RDI:
return r.rdi, nil
case x86asm.R8:
return r.r8, nil
case x86asm.R9:
return r.r9, nil
case x86asm.R10:
return r.r10, nil
case x86asm.R11:
return r.r11, nil
case x86asm.R12:
return r.r12, nil
case x86asm.R13:
return r.r13, nil
case x86asm.R14:
return r.r14, nil
case x86asm.R15:
return r.r15, nil
}
return 0, proc.ErrUnknownRegister
}
func registers(thread *Thread, floatingPoint bool) (proc.Registers, error) {
var state C.x86_thread_state64_t
var identity C.thread_identifier_info_data_t
kret := C.get_registers(C.mach_port_name_t(thread.os.threadAct), &state)
if kret != C.KERN_SUCCESS {
return nil, fmt.Errorf("could not get registers")
}
kret = C.get_identity(C.mach_port_name_t(thread.os.threadAct), &identity)
if kret != C.KERN_SUCCESS {
return nil, fmt.Errorf("could not get thread identity informations")
}
/*
thread_identifier_info::thread_handle contains the base of the
thread-specific data area, which on x86 and x86_64 is the threads base
address of the %gs segment. 10.9.2 xnu-2422.90.20/osfmk/kern/thread.c
thread_info_internal() gets the value from
machine_thread::cthread_self, which is the same value used to set the
%gs base in xnu-2422.90.20/osfmk/i386/pcb_native.c
act_machine_switch_pcb().
--
comment copied from chromium's crashpad
https://chromium.googlesource.com/crashpad/crashpad/+/master/snapshot/mac/process_reader.cc
*/
regs := &Regs{
rax: uint64(state.__rax),
rbx: uint64(state.__rbx),
rcx: uint64(state.__rcx),
rdx: uint64(state.__rdx),
rdi: uint64(state.__rdi),
rsi: uint64(state.__rsi),
rbp: uint64(state.__rbp),
rsp: uint64(state.__rsp),
r8: uint64(state.__r8),
r9: uint64(state.__r9),
r10: uint64(state.__r10),
r11: uint64(state.__r11),
r12: uint64(state.__r12),
r13: uint64(state.__r13),
r14: uint64(state.__r14),
r15: uint64(state.__r15),
rip: uint64(state.__rip),
rflags: uint64(state.__rflags),
cs: uint64(state.__cs),
fs: uint64(state.__fs),
gs: uint64(state.__gs),
gsBase: uint64(identity.thread_handle),
}
if floatingPoint {
// https://opensource.apple.com/source/xnu/xnu-792.13.8/osfmk/mach/i386/thread_status.h?txt
var fpstate C.x86_float_state64_t
kret = C.get_fpu_registers(C.mach_port_name_t(thread.os.threadAct), &fpstate)
if kret != C.KERN_SUCCESS {
return nil, fmt.Errorf("could not get floating point registers")
}
regs.fpregs = proc.AppendWordReg(regs.fpregs, "CW", *((*uint16)(unsafe.Pointer(&fpstate.__fpu_fcw))))
regs.fpregs = proc.AppendWordReg(regs.fpregs, "SW", *((*uint16)(unsafe.Pointer(&fpstate.__fpu_fsw))))
regs.fpregs = proc.AppendWordReg(regs.fpregs, "TW", uint16(fpstate.__fpu_ftw))
regs.fpregs = proc.AppendWordReg(regs.fpregs, "FOP", uint16(fpstate.__fpu_fop))
regs.fpregs = proc.AppendQwordReg(regs.fpregs, "FIP", uint64(fpstate.__fpu_cs)<<32|uint64(fpstate.__fpu_ip))
regs.fpregs = proc.AppendQwordReg(regs.fpregs, "FDP", uint64(fpstate.__fpu_ds)<<32|uint64(fpstate.__fpu_dp))
for i, st := range []*C.char{&fpstate.__fpu_stmm0.__mmst_reg[0], &fpstate.__fpu_stmm1.__mmst_reg[0], &fpstate.__fpu_stmm2.__mmst_reg[0], &fpstate.__fpu_stmm3.__mmst_reg[0], &fpstate.__fpu_stmm4.__mmst_reg[0], &fpstate.__fpu_stmm5.__mmst_reg[0], &fpstate.__fpu_stmm6.__mmst_reg[0], &fpstate.__fpu_stmm7.__mmst_reg[0]} {
stb := C.GoBytes(unsafe.Pointer(st), 10)
mantissa := binary.LittleEndian.Uint64(stb[:8])
exponent := binary.LittleEndian.Uint16(stb[8:])
regs.fpregs = proc.AppendX87Reg(regs.fpregs, i, exponent, mantissa)
}
regs.fpregs = proc.AppendMxcsrReg(regs.fpregs, "MXCSR", uint64(fpstate.__fpu_mxcsr))
regs.fpregs = proc.AppendDwordReg(regs.fpregs, "MXCSR_MASK", uint32(fpstate.__fpu_mxcsrmask))
for i, xmm := range []*C.char{&fpstate.__fpu_xmm0.__xmm_reg[0], &fpstate.__fpu_xmm1.__xmm_reg[0], &fpstate.__fpu_xmm2.__xmm_reg[0], &fpstate.__fpu_xmm3.__xmm_reg[0], &fpstate.__fpu_xmm4.__xmm_reg[0], &fpstate.__fpu_xmm5.__xmm_reg[0], &fpstate.__fpu_xmm6.__xmm_reg[0], &fpstate.__fpu_xmm7.__xmm_reg[0], &fpstate.__fpu_xmm8.__xmm_reg[0], &fpstate.__fpu_xmm9.__xmm_reg[0], &fpstate.__fpu_xmm10.__xmm_reg[0], &fpstate.__fpu_xmm11.__xmm_reg[0], &fpstate.__fpu_xmm12.__xmm_reg[0], &fpstate.__fpu_xmm13.__xmm_reg[0], &fpstate.__fpu_xmm14.__xmm_reg[0], &fpstate.__fpu_xmm15.__xmm_reg[0]} {
regs.fpregs = proc.AppendSSEReg(regs.fpregs, fmt.Sprintf("XMM%d", i), C.GoBytes(unsafe.Pointer(xmm), 16))
}
}
return regs, nil
}
func (r *Regs) Copy() proc.Registers {
//TODO(aarzilli): implement this to support function calls
return nil
}

View File

@ -0,0 +1,87 @@
package native
import (
"fmt"
sys "golang.org/x/sys/unix"
"github.com/go-delve/delve/pkg/proc"
"github.com/go-delve/delve/pkg/proc/linutil"
)
// SetPC sets RIP to the value specified by 'pc'.
func (thread *Thread) SetPC(pc uint64) error {
ir, err := registers(thread, false)
if err != nil {
return err
}
r := ir.(*linutil.AMD64Registers)
r.Regs.Rip = pc
thread.dbp.execPtraceFunc(func() { err = sys.PtraceSetRegs(thread.ID, (*sys.PtraceRegs)(r.Regs)) })
return err
}
// SetSP sets RSP to the value specified by 'sp'
func (thread *Thread) SetSP(sp uint64) (err error) {
var ir proc.Registers
ir, err = registers(thread, false)
if err != nil {
return err
}
r := ir.(*linutil.AMD64Registers)
r.Regs.Rsp = sp
thread.dbp.execPtraceFunc(func() { err = sys.PtraceSetRegs(thread.ID, (*sys.PtraceRegs)(r.Regs)) })
return
}
func (thread *Thread) SetDX(dx uint64) (err error) {
var ir proc.Registers
ir, err = registers(thread, false)
if err != nil {
return err
}
r := ir.(*linutil.AMD64Registers)
r.Regs.Rdx = dx
thread.dbp.execPtraceFunc(func() { err = sys.PtraceSetRegs(thread.ID, (*sys.PtraceRegs)(r.Regs)) })
return
}
func registers(thread *Thread, floatingPoint bool) (proc.Registers, error) {
var (
regs linutil.AMD64PtraceRegs
err error
)
thread.dbp.execPtraceFunc(func() { err = sys.PtraceGetRegs(thread.ID, (*sys.PtraceRegs)(&regs)) })
if err != nil {
return nil, err
}
r := &linutil.AMD64Registers{&regs, nil, nil}
if floatingPoint {
var fpregset linutil.AMD64Xstate
r.Fpregs, fpregset, err = thread.fpRegisters()
r.Fpregset = &fpregset
if err != nil {
return nil, err
}
}
return r, nil
}
const (
_X86_XSTATE_MAX_SIZE = 2688
_NT_X86_XSTATE = 0x202
_XSAVE_HEADER_START = 512
_XSAVE_HEADER_LEN = 64
_XSAVE_EXTENDED_REGION_START = 576
_XSAVE_SSE_REGION_LEN = 416
)
func (thread *Thread) fpRegisters() (regs []proc.Register, fpregs linutil.AMD64Xstate, err error) {
thread.dbp.execPtraceFunc(func() { fpregs, err = PtraceGetRegset(thread.ID) })
regs = fpregs.Decode()
if err != nil {
err = fmt.Errorf("could not get floating point registers: %v", err.Error())
}
return
}

View File

@ -0,0 +1,71 @@
package native
import (
"fmt"
"unsafe"
"github.com/go-delve/delve/pkg/proc"
"github.com/go-delve/delve/pkg/proc/winutil"
)
// SetPC sets the RIP register to the value specified by `pc`.
func (thread *Thread) SetPC(pc uint64) error {
context := winutil.NewCONTEXT()
context.ContextFlags = _CONTEXT_ALL
err := _GetThreadContext(thread.os.hThread, context)
if err != nil {
return err
}
context.Rip = pc
return _SetThreadContext(thread.os.hThread, context)
}
// SetSP sets the RSP register to the value specified by `sp`.
func (thread *Thread) SetSP(sp uint64) error {
context := winutil.NewCONTEXT()
context.ContextFlags = _CONTEXT_ALL
err := _GetThreadContext(thread.os.hThread, context)
if err != nil {
return err
}
context.Rsp = sp
return _SetThreadContext(thread.os.hThread, context)
}
func (thread *Thread) SetDX(dx uint64) error {
context := winutil.NewCONTEXT()
context.ContextFlags = _CONTEXT_ALL
err := _GetThreadContext(thread.os.hThread, context)
if err != nil {
return err
}
context.Rdx = dx
return _SetThreadContext(thread.os.hThread, context)
}
func registers(thread *Thread, floatingPoint bool) (proc.Registers, error) {
context := winutil.NewCONTEXT()
context.ContextFlags = _CONTEXT_ALL
err := _GetThreadContext(thread.os.hThread, context)
if err != nil {
return nil, err
}
var threadInfo _THREAD_BASIC_INFORMATION
status := _NtQueryInformationThread(thread.os.hThread, _ThreadBasicInformation, uintptr(unsafe.Pointer(&threadInfo)), uint32(unsafe.Sizeof(threadInfo)), nil)
if !_NT_SUCCESS(status) {
return nil, fmt.Errorf("NtQueryInformationThread failed: it returns 0x%x", status)
}
return winutil.NewAMD64Registers(context, uint64(threadInfo.TebBaseAddress), floatingPoint), nil
}

View File

@ -0,0 +1,119 @@
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go
package native
import (
"syscall"
"github.com/go-delve/delve/pkg/proc/winutil"
)
type _NTSTATUS int32
type _CLIENT_ID struct {
UniqueProcess syscall.Handle
UniqueThread syscall.Handle
}
type _THREAD_BASIC_INFORMATION struct {
ExitStatus _NTSTATUS
TebBaseAddress uintptr
ClientId _CLIENT_ID
AffinityMask uintptr
Priority int32
BasePriority int32
}
type _CREATE_PROCESS_DEBUG_INFO struct {
File syscall.Handle
Process syscall.Handle
Thread syscall.Handle
BaseOfImage uintptr
DebugInfoFileOffset uint32
DebugInfoSize uint32
ThreadLocalBase uintptr
StartAddress uintptr
ImageName uintptr
Unicode uint16
}
type _CREATE_THREAD_DEBUG_INFO struct {
Thread syscall.Handle
ThreadLocalBase uintptr
StartAddress uintptr
}
type _EXIT_PROCESS_DEBUG_INFO struct {
ExitCode uint32
}
type _LOAD_DLL_DEBUG_INFO struct {
File syscall.Handle
BaseOfDll uintptr
DebugInfoFileOffset uint32
DebugInfoSize uint32
ImageName uintptr
Unicode uint16
}
type _EXCEPTION_DEBUG_INFO struct {
ExceptionRecord _EXCEPTION_RECORD
FirstChance uint32
}
type _EXCEPTION_RECORD struct {
ExceptionCode uint32
ExceptionFlags uint32
ExceptionRecord *_EXCEPTION_RECORD
ExceptionAddress uintptr
NumberParameters uint32
ExceptionInformation [_EXCEPTION_MAXIMUM_PARAMETERS]uintptr
}
const (
_ThreadBasicInformation = 0
_DBG_CONTINUE = 0x00010002
_DBG_EXCEPTION_NOT_HANDLED = 0x80010001
_EXCEPTION_DEBUG_EVENT = 1
_CREATE_THREAD_DEBUG_EVENT = 2
_CREATE_PROCESS_DEBUG_EVENT = 3
_EXIT_THREAD_DEBUG_EVENT = 4
_EXIT_PROCESS_DEBUG_EVENT = 5
_LOAD_DLL_DEBUG_EVENT = 6
_UNLOAD_DLL_DEBUG_EVENT = 7
_OUTPUT_DEBUG_STRING_EVENT = 8
_RIP_EVENT = 9
// DEBUG_ONLY_THIS_PROCESS tracks https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx
_DEBUG_ONLY_THIS_PROCESS = 0x00000002
_EXCEPTION_BREAKPOINT = 0x80000003
_EXCEPTION_SINGLE_STEP = 0x80000004
_EXCEPTION_MAXIMUM_PARAMETERS = 15
)
func _NT_SUCCESS(x _NTSTATUS) bool {
return x >= 0
}
// zsyscall_windows.go, an autogenerated file, wants to refer to the context
// structure as _CONTEXT, but we need to have it in pkg/proc/winutil.CONTEXT
// because it's also used on non-windows operating systems.
type _CONTEXT = winutil.CONTEXT
//sys _NtQueryInformationThread(threadHandle syscall.Handle, infoclass int32, info uintptr, infolen uint32, retlen *uint32) (status _NTSTATUS) = ntdll.NtQueryInformationThread
//sys _GetThreadContext(thread syscall.Handle, context *_CONTEXT) (err error) = kernel32.GetThreadContext
//sys _SetThreadContext(thread syscall.Handle, context *_CONTEXT) (err error) = kernel32.SetThreadContext
//sys _SuspendThread(threadid syscall.Handle) (prevsuspcount uint32, err error) [failretval==0xffffffff] = kernel32.SuspendThread
//sys _ResumeThread(threadid syscall.Handle) (prevsuspcount uint32, err error) [failretval==0xffffffff] = kernel32.ResumeThread
//sys _ContinueDebugEvent(processid uint32, threadid uint32, continuestatus uint32) (err error) = kernel32.ContinueDebugEvent
//sys _WriteProcessMemory(process syscall.Handle, baseaddr uintptr, buffer *byte, size uintptr, byteswritten *uintptr) (err error) = kernel32.WriteProcessMemory
//sys _ReadProcessMemory(process syscall.Handle, baseaddr uintptr, buffer *byte, size uintptr, bytesread *uintptr) (err error) = kernel32.ReadProcessMemory
//sys _DebugBreakProcess(process syscall.Handle) (err error) = kernel32.DebugBreakProcess
//sys _WaitForDebugEvent(debugevent *_DEBUG_EVENT, milliseconds uint32) (err error) = kernel32.WaitForDebugEvent
//sys _DebugActiveProcess(processid uint32) (err error) = kernel32.DebugActiveProcess
//sys _DebugActiveProcessStop(processid uint32) (err error) = kernel32.DebugActiveProcessStop
//sys _QueryFullProcessImageName(process syscall.Handle, flags uint32, exename *uint16, size *uint32) (err error) = kernel32.QueryFullProcessImageNameW

View File

@ -0,0 +1,24 @@
package native
const (
_CONTEXT_AMD64 = 0x100000
_CONTEXT_CONTROL = (_CONTEXT_AMD64 | 0x1)
_CONTEXT_INTEGER = (_CONTEXT_AMD64 | 0x2)
_CONTEXT_SEGMENTS = (_CONTEXT_AMD64 | 0x4)
_CONTEXT_FLOATING_POINT = (_CONTEXT_AMD64 | 0x8)
_CONTEXT_DEBUG_REGISTERS = (_CONTEXT_AMD64 | 0x10)
_CONTEXT_FULL = (_CONTEXT_CONTROL | _CONTEXT_INTEGER | _CONTEXT_FLOATING_POINT)
_CONTEXT_ALL = (_CONTEXT_CONTROL | _CONTEXT_INTEGER | _CONTEXT_SEGMENTS | _CONTEXT_FLOATING_POINT | _CONTEXT_DEBUG_REGISTERS)
_CONTEXT_EXCEPTION_ACTIVE = 0x8000000
_CONTEXT_SERVICE_ACTIVE = 0x10000000
_CONTEXT_EXCEPTION_REQUEST = 0x40000000
_CONTEXT_EXCEPTION_REPORTING = 0x80000000
)
type _DEBUG_EVENT struct {
DebugEventCode uint32
ProcessId uint32
ThreadId uint32
_ uint32 // to align Union properly
U [160]byte
}

View File

@ -0,0 +1,174 @@
package native
import (
"fmt"
"github.com/go-delve/delve/pkg/proc"
)
// Thread represents a single thread in the traced process
// ID represents the thread id or port, Process holds a reference to the
// Process struct that contains info on the process as
// a whole, and Status represents the last result of a `wait` call
// on this thread.
type Thread struct {
ID int // Thread ID or mach port
Status *WaitStatus // Status returned from last wait call
CurrentBreakpoint proc.BreakpointState // Breakpoint thread is currently stopped at
dbp *Process
singleStepping bool
os *OSSpecificDetails
common proc.CommonThread
}
// Continue the execution of this thread.
//
// If we are currently at a breakpoint, we'll clear it
// first and then resume execution. Thread will continue until
// it hits a breakpoint or is signaled.
func (t *Thread) Continue() error {
pc, err := t.PC()
if err != nil {
return err
}
// Check whether we are stopped at a breakpoint, and
// if so, single step over it before continuing.
if _, ok := t.dbp.FindBreakpoint(pc); ok {
if err := t.StepInstruction(); err != nil {
return err
}
}
return t.resume()
}
// StepInstruction steps a single instruction.
//
// Executes exactly one instruction and then returns.
// If the thread is at a breakpoint, we first clear it,
// execute the instruction, and then replace the breakpoint.
// Otherwise we simply execute the next instruction.
func (t *Thread) StepInstruction() (err error) {
t.singleStepping = true
defer func() {
t.singleStepping = false
}()
pc, err := t.PC()
if err != nil {
return err
}
bp, ok := t.dbp.FindBreakpoint(pc)
if ok {
// Clear the breakpoint so that we can continue execution.
err = t.ClearBreakpoint(bp)
if err != nil {
return err
}
// Restore breakpoint now that we have passed it.
defer func() {
err = t.dbp.writeSoftwareBreakpoint(t, bp.Addr)
}()
}
err = t.singleStep()
if err != nil {
if _, exited := err.(proc.ErrProcessExited); exited {
return err
}
return fmt.Errorf("step failed: %s", err.Error())
}
return nil
}
// Location returns the threads location, including the file:line
// of the corresponding source code, the function we're in
// and the current instruction address.
func (t *Thread) Location() (*proc.Location, error) {
pc, err := t.PC()
if err != nil {
return nil, err
}
f, l, fn := t.dbp.bi.PCToLine(pc)
return &proc.Location{PC: pc, File: f, Line: l, Fn: fn}, nil
}
// Arch returns the architecture the binary is
// compiled for and executing on.
func (t *Thread) Arch() proc.Arch {
return t.dbp.bi.Arch
}
// BinInfo returns information on the binary.
func (t *Thread) BinInfo() *proc.BinaryInfo {
return t.dbp.bi
}
// Common returns information common across Process
// implementations.
func (t *Thread) Common() *proc.CommonThread {
return &t.common
}
// SetCurrentBreakpoint sets the current breakpoint that this
// thread is stopped at as CurrentBreakpoint on the thread struct.
func (t *Thread) SetCurrentBreakpoint() error {
t.CurrentBreakpoint.Clear()
pc, err := t.PC()
if err != nil {
return err
}
if bp, ok := t.dbp.FindBreakpoint(pc); ok {
if err = t.SetPC(bp.Addr); err != nil {
return err
}
t.CurrentBreakpoint = bp.CheckCondition(t)
if t.CurrentBreakpoint.Breakpoint != nil && t.CurrentBreakpoint.Active {
if g, err := proc.GetG(t); err == nil {
t.CurrentBreakpoint.HitCount[g.ID]++
}
t.CurrentBreakpoint.TotalHitCount++
}
}
return nil
}
// Breakpoint returns the current breakpoint that is active
// on this thread.
func (t *Thread) Breakpoint() proc.BreakpointState {
return t.CurrentBreakpoint
}
// ThreadID returns the ID of this thread.
func (t *Thread) ThreadID() int {
return t.ID
}
// ClearBreakpoint clears the specified breakpoint.
func (t *Thread) ClearBreakpoint(bp *proc.Breakpoint) error {
if _, err := t.WriteMemory(uintptr(bp.Addr), bp.OriginalData); err != nil {
return fmt.Errorf("could not clear breakpoint %s", err)
}
return nil
}
// Registers obtains register values from the debugged process.
func (t *Thread) Registers(floatingPoint bool) (proc.Registers, error) {
return registers(t, floatingPoint)
}
// RestoreRegisters will set the value of the CPU registers to those
// passed in via 'savedRegs'.
func (t *Thread) RestoreRegisters(savedRegs proc.Registers) error {
return t.restoreRegisters(savedRegs)
}
// PC returns the current program counter value for this thread.
func (t *Thread) PC() (uint64, error) {
regs, err := t.Registers(false)
if err != nil {
return 0, err
}
return regs.PC(), nil
}

View File

@ -0,0 +1,179 @@
//+build darwin,macnative
#include "threads_darwin.h"
int
write_memory(task_t task, mach_vm_address_t addr, void *d, mach_msg_type_number_t len) {
kern_return_t kret;
vm_region_submap_short_info_data_64_t info;
mach_msg_type_number_t count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
mach_vm_size_t l = len;
mach_port_t objname;
if (len == 1) l = 2;
kret = mach_vm_region((vm_map_t)task, &(mach_vm_address_t){addr}, (mach_vm_size_t*)&l, VM_REGION_BASIC_INFO_64, (vm_region_info_t)&info, &count, &objname);
if (kret != KERN_SUCCESS) return -1;
// Set permissions to enable writting to this memory location
kret = mach_vm_protect(task, addr, len, FALSE, VM_PROT_WRITE|VM_PROT_COPY|VM_PROT_READ);
if (kret != KERN_SUCCESS) return -1;
kret = mach_vm_write((vm_map_t)task, addr, (vm_offset_t)d, len);
if (kret != KERN_SUCCESS) return -1;
// Restore virtual memory permissions
kret = mach_vm_protect(task, addr, len, FALSE, info.protection);
if (kret != KERN_SUCCESS) return -1;
return 0;
}
int
read_memory(task_t task, mach_vm_address_t addr, void *d, mach_msg_type_number_t len) {
kern_return_t kret;
pointer_t data;
mach_msg_type_number_t count;
kret = mach_vm_read((vm_map_t)task, addr, len, &data, &count);
if (kret != KERN_SUCCESS) return -1;
memcpy(d, (void *)data, len);
kret = vm_deallocate(task, data, len);
if (kret != KERN_SUCCESS) return -1;
return count;
}
kern_return_t
get_registers(mach_port_name_t task, x86_thread_state64_t *state) {
kern_return_t kret;
mach_msg_type_number_t stateCount = x86_THREAD_STATE64_COUNT;
// TODO(dp) - possible memory leak - vm_deallocate state
return thread_get_state(task, x86_THREAD_STATE64, (thread_state_t)state, &stateCount);
}
kern_return_t
get_fpu_registers(mach_port_name_t task, x86_float_state64_t *state) {
kern_return_t kret;
mach_msg_type_number_t stateCount = x86_FLOAT_STATE64_COUNT;
return thread_get_state(task, x86_FLOAT_STATE64, (thread_state_t)state, &stateCount);
}
kern_return_t
get_identity(mach_port_name_t task, thread_identifier_info_data_t *idinfo) {
mach_msg_type_number_t idinfoCount = THREAD_IDENTIFIER_INFO_COUNT;
return thread_info(task, THREAD_IDENTIFIER_INFO, (thread_info_t)idinfo, &idinfoCount);
}
kern_return_t
set_registers(mach_port_name_t task, x86_thread_state64_t *state) {
mach_msg_type_number_t stateCount = x86_THREAD_STATE64_COUNT;
return thread_set_state(task, x86_THREAD_STATE64, (thread_state_t)state, stateCount);
}
kern_return_t
set_pc(thread_act_t task, uint64_t pc) {
kern_return_t kret;
x86_thread_state64_t state;
mach_msg_type_number_t stateCount = x86_THREAD_STATE64_COUNT;
kret = thread_get_state(task, x86_THREAD_STATE64, (thread_state_t)&state, &stateCount);
if (kret != KERN_SUCCESS) return kret;
state.__rip = pc;
return thread_set_state(task, x86_THREAD_STATE64, (thread_state_t)&state, stateCount);
}
kern_return_t
single_step(thread_act_t thread) {
kern_return_t kret;
x86_thread_state64_t regs;
mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT;
kret = thread_get_state(thread, x86_THREAD_STATE64, (thread_state_t)&regs, &count);
if (kret != KERN_SUCCESS) return kret;
// Set trap bit in rflags
regs.__rflags |= 0x100UL;
kret = thread_set_state(thread, x86_THREAD_STATE64, (thread_state_t)&regs, count);
if (kret != KERN_SUCCESS) return kret;
return resume_thread(thread);
}
kern_return_t
resume_thread(thread_act_t thread) {
kern_return_t kret;
struct thread_basic_info info;
unsigned int info_count = THREAD_BASIC_INFO_COUNT;
kret = thread_info((thread_t)thread, THREAD_BASIC_INFO, (thread_info_t)&info, &info_count);
if (kret != KERN_SUCCESS) return kret;
for (int i = 0; i < info.suspend_count; i++) {
kret = thread_resume(thread);
if (kret != KERN_SUCCESS) return kret;
}
return KERN_SUCCESS;
}
kern_return_t
clear_trap_flag(thread_act_t thread) {
kern_return_t kret;
x86_thread_state64_t regs;
mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT;
kret = thread_get_state(thread, x86_THREAD_STATE64, (thread_state_t)&regs, &count);
if (kret != KERN_SUCCESS) return kret;
// Clear trap bit in rflags
regs.__rflags ^= 0x100UL;
return thread_set_state(thread, x86_THREAD_STATE64, (thread_state_t)&regs, count);
}
int
thread_blocked(thread_act_t thread) {
kern_return_t kret;
struct thread_basic_info info;
unsigned int info_count = THREAD_BASIC_INFO_COUNT;
kret = thread_info((thread_t)thread, THREAD_BASIC_INFO, (thread_info_t)&info, &info_count);
if (kret != KERN_SUCCESS) return -1;
return info.suspend_count;
}
int
num_running_threads(task_t task) {
kern_return_t kret;
thread_act_array_t list;
mach_msg_type_number_t count;
int i, n = 0;
kret = task_threads(task, &list, &count);
if (kret != KERN_SUCCESS) {
return -kret;
}
for (i = 0; i < count; ++i) {
thread_act_t thread = list[i];
struct thread_basic_info info;
unsigned int info_count = THREAD_BASIC_INFO_COUNT;
kret = thread_info((thread_t)thread, THREAD_BASIC_INFO, (thread_info_t)&info, &info_count);
if (kret == KERN_SUCCESS) {
if (info.suspend_count == 0) {
++n;
} else {
}
}
}
kret = vm_deallocate(mach_task_self(), (vm_address_t) list, count * sizeof(list[0]));
if (kret != KERN_SUCCESS) return -kret;
return n;
}

View File

@ -0,0 +1,153 @@
//+build darwin,macnative
package native
// #include "threads_darwin.h"
// #include "proc_darwin.h"
import "C"
import (
"errors"
"fmt"
"unsafe"
sys "golang.org/x/sys/unix"
"github.com/go-delve/delve/pkg/proc"
)
// WaitStatus is a synonym for the platform-specific WaitStatus
type WaitStatus sys.WaitStatus
// OSSpecificDetails holds information specific to the OSX/Darwin
// operating system / kernel.
type OSSpecificDetails struct {
threadAct C.thread_act_t
registers C.x86_thread_state64_t
exists bool
}
// ErrContinueThread is the error returned when a thread could not
// be continued.
var ErrContinueThread = fmt.Errorf("could not continue thread")
func (t *Thread) stop() (err error) {
kret := C.thread_suspend(t.os.threadAct)
if kret != C.KERN_SUCCESS {
errStr := C.GoString(C.mach_error_string(C.mach_error_t(kret)))
// check that the thread still exists before complaining
err2 := t.dbp.updateThreadList()
if err2 != nil {
err = fmt.Errorf("could not suspend thread %d %s (additionally could not update thread list: %v)", t.ID, errStr, err2)
return
}
if _, ok := t.dbp.threads[t.ID]; ok {
err = fmt.Errorf("could not suspend thread %d %s", t.ID, errStr)
return
}
}
return
}
func (t *Thread) singleStep() error {
kret := C.single_step(t.os.threadAct)
if kret != C.KERN_SUCCESS {
return fmt.Errorf("could not single step")
}
for {
twthread, err := t.dbp.trapWait(t.dbp.pid)
if err != nil {
return err
}
if twthread.ID == t.ID {
break
}
}
kret = C.clear_trap_flag(t.os.threadAct)
if kret != C.KERN_SUCCESS {
return fmt.Errorf("could not clear CPU trap flag")
}
return nil
}
func (t *Thread) resume() error {
// TODO(dp) set flag for ptrace stops
var err error
t.dbp.execPtraceFunc(func() { err = PtraceCont(t.dbp.pid, 0) })
if err == nil {
return nil
}
kret := C.resume_thread(t.os.threadAct)
if kret != C.KERN_SUCCESS {
return ErrContinueThread
}
return nil
}
func (t *Thread) Blocked() bool {
// TODO(dp) cache the func pc to remove this lookup
regs, err := t.Registers(false)
if err != nil {
return false
}
pc := regs.PC()
fn := t.BinInfo().PCToFunc(pc)
if fn == nil {
return false
}
switch fn.Name {
case "runtime.kevent", "runtime.mach_semaphore_wait", "runtime.usleep", "runtime.mach_semaphore_timedwait":
return true
default:
return false
}
}
// Stopped returns whether the thread is stopped at
// the operating system level.
func (t *Thread) Stopped() bool {
return C.thread_blocked(t.os.threadAct) > C.int(0)
}
func (t *Thread) WriteMemory(addr uintptr, data []byte) (int, error) {
if t.dbp.exited {
return 0, proc.ErrProcessExited{Pid: t.dbp.pid}
}
if len(data) == 0 {
return 0, nil
}
var (
vmData = unsafe.Pointer(&data[0])
vmAddr = C.mach_vm_address_t(addr)
length = C.mach_msg_type_number_t(len(data))
)
if ret := C.write_memory(t.dbp.os.task, vmAddr, vmData, length); ret < 0 {
return 0, fmt.Errorf("could not write memory")
}
return len(data), nil
}
func (t *Thread) ReadMemory(buf []byte, addr uintptr) (int, error) {
if t.dbp.exited {
return 0, proc.ErrProcessExited{Pid: t.dbp.pid}
}
if len(buf) == 0 {
return 0, nil
}
var (
vmData = unsafe.Pointer(&buf[0])
vmAddr = C.mach_vm_address_t(addr)
length = C.mach_msg_type_number_t(len(buf))
)
ret := C.read_memory(t.dbp.os.task, vmAddr, vmData, length)
if ret < 0 {
return 0, fmt.Errorf("could not read memory")
}
return len(buf), nil
}
func (t *Thread) restoreRegisters(sr proc.Registers) error {
return errors.New("not implemented")
}

View File

@ -0,0 +1,43 @@
//+build darwin,macnative
#include <stdlib.h>
#include <sys/types.h>
#include <mach/mach.h>
#include <mach/mach_vm.h>
#include <mach/thread_info.h>
int
write_memory(task_t, mach_vm_address_t, void *, mach_msg_type_number_t);
int
read_memory(task_t, mach_vm_address_t, void *, mach_msg_type_number_t);
kern_return_t
get_registers(mach_port_name_t, x86_thread_state64_t*);
kern_return_t
get_fpu_registers(mach_port_name_t, x86_float_state64_t *);
kern_return_t
set_pc(thread_act_t, uint64_t);
kern_return_t
single_step(thread_act_t);
kern_return_t
clear_trap_flag(thread_act_t);
kern_return_t
resume_thread(thread_act_t);
kern_return_t
set_registers(mach_port_name_t, x86_thread_state64_t*);
kern_return_t
get_identity(mach_port_name_t, thread_identifier_info_data_t *);
int
thread_blocked(thread_act_t thread);
int
num_running_threads(task_t task);

View File

@ -0,0 +1,133 @@
package native
import (
"fmt"
"syscall"
"unsafe"
sys "golang.org/x/sys/unix"
"github.com/go-delve/delve/pkg/proc"
"github.com/go-delve/delve/pkg/proc/linutil"
)
type WaitStatus sys.WaitStatus
// OSSpecificDetails hold Linux specific
// process details.
type OSSpecificDetails struct {
registers sys.PtraceRegs
running bool
}
func (t *Thread) stop() (err error) {
err = sys.Tgkill(t.dbp.pid, t.ID, sys.SIGSTOP)
if err != nil {
err = fmt.Errorf("stop err %s on thread %d", err, t.ID)
return
}
return
}
// Stopped returns whether the thread is stopped at
// the operating system level.
func (t *Thread) Stopped() bool {
state := status(t.ID, t.dbp.os.comm)
return state == StatusTraceStop || state == StatusTraceStopT
}
func (t *Thread) resume() error {
return t.resumeWithSig(0)
}
func (t *Thread) resumeWithSig(sig int) (err error) {
t.os.running = true
t.dbp.execPtraceFunc(func() { err = PtraceCont(t.ID, sig) })
return
}
func (t *Thread) singleStep() (err error) {
for {
t.dbp.execPtraceFunc(func() { err = sys.PtraceSingleStep(t.ID) })
if err != nil {
return err
}
wpid, status, err := t.dbp.waitFast(t.ID)
if err != nil {
return err
}
if (status == nil || status.Exited()) && wpid == t.dbp.pid {
t.dbp.postExit()
rs := 0
if status != nil {
rs = status.ExitStatus()
}
return proc.ErrProcessExited{Pid: t.dbp.pid, Status: rs}
}
if wpid == t.ID && status.StopSignal() == sys.SIGTRAP {
return nil
}
}
}
func (t *Thread) Blocked() bool {
regs, err := t.Registers(false)
if err != nil {
return false
}
pc := regs.PC()
fn := t.BinInfo().PCToFunc(pc)
if fn != nil && ((fn.Name == "runtime.futex") || (fn.Name == "runtime.usleep") || (fn.Name == "runtime.clone")) {
return true
}
return false
}
func (t *Thread) restoreRegisters(savedRegs proc.Registers) error {
sr := savedRegs.(*linutil.AMD64Registers)
var restoreRegistersErr error
t.dbp.execPtraceFunc(func() {
restoreRegistersErr = sys.PtraceSetRegs(t.ID, (*sys.PtraceRegs)(sr.Regs))
if restoreRegistersErr != nil {
return
}
if sr.Fpregset.Xsave != nil {
iov := sys.Iovec{Base: &sr.Fpregset.Xsave[0], Len: uint64(len(sr.Fpregset.Xsave))}
_, _, restoreRegistersErr = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_SETREGSET, uintptr(t.ID), _NT_X86_XSTATE, uintptr(unsafe.Pointer(&iov)), 0, 0)
return
}
_, _, restoreRegistersErr = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_SETFPREGS, uintptr(t.ID), uintptr(0), uintptr(unsafe.Pointer(&sr.Fpregset.AMD64PtraceFpRegs)), 0, 0)
return
})
if restoreRegistersErr == syscall.Errno(0) {
restoreRegistersErr = nil
}
return restoreRegistersErr
}
func (t *Thread) WriteMemory(addr uintptr, data []byte) (written int, err error) {
if t.dbp.exited {
return 0, proc.ErrProcessExited{Pid: t.dbp.pid}
}
if len(data) == 0 {
return
}
t.dbp.execPtraceFunc(func() { written, err = sys.PtracePokeData(t.ID, addr, data) })
return
}
func (t *Thread) ReadMemory(data []byte, addr uintptr) (n int, err error) {
if t.dbp.exited {
return 0, proc.ErrProcessExited{Pid: t.dbp.pid}
}
if len(data) == 0 {
return
}
t.dbp.execPtraceFunc(func() { _, err = sys.PtracePeekData(t.ID, addr, data) })
if err == nil {
n = len(data)
}
return
}

View File

@ -0,0 +1,159 @@
package native
import (
"errors"
"syscall"
sys "golang.org/x/sys/windows"
"github.com/go-delve/delve/pkg/proc"
"github.com/go-delve/delve/pkg/proc/winutil"
)
// WaitStatus is a synonym for the platform-specific WaitStatus
type WaitStatus sys.WaitStatus
// OSSpecificDetails holds information specific to the Windows
// operating system / kernel.
type OSSpecificDetails struct {
hThread syscall.Handle
}
func (t *Thread) singleStep() error {
context := winutil.NewCONTEXT()
context.ContextFlags = _CONTEXT_ALL
// Set the processor TRAP flag
err := _GetThreadContext(t.os.hThread, context)
if err != nil {
return err
}
context.EFlags |= 0x100
err = _SetThreadContext(t.os.hThread, context)
if err != nil {
return err
}
_, err = _ResumeThread(t.os.hThread)
if err != nil {
return err
}
for {
var tid, exitCode int
t.dbp.execPtraceFunc(func() {
tid, exitCode, err = t.dbp.waitForDebugEvent(waitBlocking | waitSuspendNewThreads)
})
if err != nil {
return err
}
if tid == 0 {
t.dbp.postExit()
return proc.ErrProcessExited{Pid: t.dbp.pid, Status: exitCode}
}
if t.dbp.os.breakThread == t.ID {
break
}
t.dbp.execPtraceFunc(func() {
err = _ContinueDebugEvent(uint32(t.dbp.pid), uint32(t.dbp.os.breakThread), _DBG_CONTINUE)
})
}
_, err = _SuspendThread(t.os.hThread)
if err != nil {
return err
}
t.dbp.execPtraceFunc(func() {
err = _ContinueDebugEvent(uint32(t.dbp.pid), uint32(t.ID), _DBG_CONTINUE)
})
if err != nil {
return err
}
// Unset the processor TRAP flag
err = _GetThreadContext(t.os.hThread, context)
if err != nil {
return err
}
context.EFlags &= ^uint32(0x100)
return _SetThreadContext(t.os.hThread, context)
}
func (t *Thread) resume() error {
var err error
t.dbp.execPtraceFunc(func() {
//TODO: Note that we are ignoring the thread we were asked to continue and are continuing the
//thread that we last broke on.
err = _ContinueDebugEvent(uint32(t.dbp.pid), uint32(t.ID), _DBG_CONTINUE)
})
return err
}
func (t *Thread) Blocked() bool {
// TODO: Probably incorrect - what are the runtime functions that
// indicate blocking on Windows?
regs, err := t.Registers(false)
if err != nil {
return false
}
pc := regs.PC()
fn := t.BinInfo().PCToFunc(pc)
if fn == nil {
return false
}
switch fn.Name {
case "runtime.kevent", "runtime.usleep":
return true
default:
return false
}
}
// Stopped returns whether the thread is stopped at the operating system
// level. On windows this always returns true.
func (t *Thread) Stopped() bool {
return true
}
func (t *Thread) WriteMemory(addr uintptr, data []byte) (int, error) {
if t.dbp.exited {
return 0, proc.ErrProcessExited{Pid: t.dbp.pid}
}
if len(data) == 0 {
return 0, nil
}
var count uintptr
err := _WriteProcessMemory(t.dbp.os.hProcess, addr, &data[0], uintptr(len(data)), &count)
if err != nil {
return 0, err
}
return int(count), nil
}
var ErrShortRead = errors.New("short read")
func (t *Thread) ReadMemory(buf []byte, addr uintptr) (int, error) {
if t.dbp.exited {
return 0, proc.ErrProcessExited{Pid: t.dbp.pid}
}
if len(buf) == 0 {
return 0, nil
}
var count uintptr
err := _ReadProcessMemory(t.dbp.os.hProcess, addr, &buf[0], uintptr(len(buf)), &count)
if err == nil && count != uintptr(len(buf)) {
err = ErrShortRead
}
return int(count), err
}
func (t *Thread) restoreRegisters(savedRegs proc.Registers) error {
return _SetThreadContext(t.os.hThread, savedRegs.(*winutil.AMD64Registers).Context)
}

View File

@ -0,0 +1,181 @@
// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
package native
import (
"syscall"
"unsafe"
)
var _ unsafe.Pointer
var (
modntdll = syscall.NewLazyDLL("ntdll.dll")
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
procNtQueryInformationThread = modntdll.NewProc("NtQueryInformationThread")
procGetThreadContext = modkernel32.NewProc("GetThreadContext")
procSetThreadContext = modkernel32.NewProc("SetThreadContext")
procSuspendThread = modkernel32.NewProc("SuspendThread")
procResumeThread = modkernel32.NewProc("ResumeThread")
procContinueDebugEvent = modkernel32.NewProc("ContinueDebugEvent")
procWriteProcessMemory = modkernel32.NewProc("WriteProcessMemory")
procReadProcessMemory = modkernel32.NewProc("ReadProcessMemory")
procDebugBreakProcess = modkernel32.NewProc("DebugBreakProcess")
procWaitForDebugEvent = modkernel32.NewProc("WaitForDebugEvent")
procDebugActiveProcess = modkernel32.NewProc("DebugActiveProcess")
procDebugActiveProcessStop = modkernel32.NewProc("DebugActiveProcessStop")
procQueryFullProcessImageNameW = modkernel32.NewProc("QueryFullProcessImageNameW")
)
func _NtQueryInformationThread(threadHandle syscall.Handle, infoclass int32, info uintptr, infolen uint32, retlen *uint32) (status _NTSTATUS) {
r0, _, _ := syscall.Syscall6(procNtQueryInformationThread.Addr(), 5, uintptr(threadHandle), uintptr(infoclass), uintptr(info), uintptr(infolen), uintptr(unsafe.Pointer(retlen)), 0)
status = _NTSTATUS(r0)
return
}
func _GetThreadContext(thread syscall.Handle, context *_CONTEXT) (err error) {
r1, _, e1 := syscall.Syscall(procGetThreadContext.Addr(), 2, uintptr(thread), uintptr(unsafe.Pointer(context)), 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func _SetThreadContext(thread syscall.Handle, context *_CONTEXT) (err error) {
r1, _, e1 := syscall.Syscall(procSetThreadContext.Addr(), 2, uintptr(thread), uintptr(unsafe.Pointer(context)), 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func _SuspendThread(threadid syscall.Handle) (prevsuspcount uint32, err error) {
r0, _, e1 := syscall.Syscall(procSuspendThread.Addr(), 1, uintptr(threadid), 0, 0)
prevsuspcount = uint32(r0)
if prevsuspcount == 0xffffffff {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func _ResumeThread(threadid syscall.Handle) (prevsuspcount uint32, err error) {
r0, _, e1 := syscall.Syscall(procResumeThread.Addr(), 1, uintptr(threadid), 0, 0)
prevsuspcount = uint32(r0)
if prevsuspcount == 0xffffffff {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func _ContinueDebugEvent(processid uint32, threadid uint32, continuestatus uint32) (err error) {
r1, _, e1 := syscall.Syscall(procContinueDebugEvent.Addr(), 3, uintptr(processid), uintptr(threadid), uintptr(continuestatus))
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func _WriteProcessMemory(process syscall.Handle, baseaddr uintptr, buffer *byte, size uintptr, byteswritten *uintptr) (err error) {
r1, _, e1 := syscall.Syscall6(procWriteProcessMemory.Addr(), 5, uintptr(process), uintptr(baseaddr), uintptr(unsafe.Pointer(buffer)), uintptr(size), uintptr(unsafe.Pointer(byteswritten)), 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func _ReadProcessMemory(process syscall.Handle, baseaddr uintptr, buffer *byte, size uintptr, bytesread *uintptr) (err error) {
r1, _, e1 := syscall.Syscall6(procReadProcessMemory.Addr(), 5, uintptr(process), uintptr(baseaddr), uintptr(unsafe.Pointer(buffer)), uintptr(size), uintptr(unsafe.Pointer(bytesread)), 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func _DebugBreakProcess(process syscall.Handle) (err error) {
r1, _, e1 := syscall.Syscall(procDebugBreakProcess.Addr(), 1, uintptr(process), 0, 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func _WaitForDebugEvent(debugevent *_DEBUG_EVENT, milliseconds uint32) (err error) {
r1, _, e1 := syscall.Syscall(procWaitForDebugEvent.Addr(), 2, uintptr(unsafe.Pointer(debugevent)), uintptr(milliseconds), 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func _DebugActiveProcess(processid uint32) (err error) {
r1, _, e1 := syscall.Syscall(procDebugActiveProcess.Addr(), 1, uintptr(processid), 0, 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func _DebugActiveProcessStop(processid uint32) (err error) {
r1, _, e1 := syscall.Syscall(procDebugActiveProcessStop.Addr(), 1, uintptr(processid), 0, 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func _QueryFullProcessImageName(process syscall.Handle, flags uint32, exename *uint16, size *uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procQueryFullProcessImageNameW.Addr(), 4, uintptr(process), uintptr(flags), uintptr(unsafe.Pointer(exename)), uintptr(unsafe.Pointer(size)), 0, 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}