mirror of
https://github.com/beego/bee.git
synced 2025-07-01 12:20:17 +00:00
Updated vendor
This commit is contained in:
283
vendor/github.com/go-delve/delve/pkg/proc/native/exc.h
generated
vendored
Normal file
283
vendor/github.com/go-delve/delve/pkg/proc/native/exc.h
generated
vendored
Normal 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_ */
|
770
vendor/github.com/go-delve/delve/pkg/proc/native/exc_user_darwin.c
generated
vendored
Normal file
770
vendor/github.com/go-delve/delve/pkg/proc/native/exc_user_darwin.c
generated
vendored
Normal 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;
|
||||
}
|
114
vendor/github.com/go-delve/delve/pkg/proc/native/exec_darwin.c
generated
vendored
Normal file
114
vendor/github.com/go-delve/delve/pkg/proc/native/exec_darwin.c
generated
vendored
Normal 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);
|
||||
}
|
12
vendor/github.com/go-delve/delve/pkg/proc/native/exec_darwin.h
generated
vendored
Normal file
12
vendor/github.com/go-delve/delve/pkg/proc/native/exec_darwin.h
generated
vendored
Normal 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*);
|
283
vendor/github.com/go-delve/delve/pkg/proc/native/mach_exc.h
generated
vendored
Normal file
283
vendor/github.com/go-delve/delve/pkg/proc/native/mach_exc.h
generated
vendored
Normal 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_ */
|
770
vendor/github.com/go-delve/delve/pkg/proc/native/mach_exc_user_darwin.c
generated
vendored
Normal file
770
vendor/github.com/go-delve/delve/pkg/proc/native/mach_exc_user_darwin.c
generated
vendored
Normal 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;
|
||||
}
|
132
vendor/github.com/go-delve/delve/pkg/proc/native/nonative_darwin.go
generated
vendored
Normal file
132
vendor/github.com/go-delve/delve/pkg/proc/native/nonative_darwin.go
generated
vendored
Normal 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 }
|
422
vendor/github.com/go-delve/delve/pkg/proc/native/proc.go
generated
vendored
Normal file
422
vendor/github.com/go-delve/delve/pkg/proc/native/proc.go
generated
vendored
Normal 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
|
||||
}
|
233
vendor/github.com/go-delve/delve/pkg/proc/native/proc_darwin.c
generated
vendored
Normal file
233
vendor/github.com/go-delve/delve/pkg/proc/native/proc_darwin.c
generated
vendored
Normal 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;
|
||||
}
|
467
vendor/github.com/go-delve/delve/pkg/proc/native/proc_darwin.go
generated
vendored
Normal file
467
vendor/github.com/go-delve/delve/pkg/proc/native/proc_darwin.go
generated
vendored
Normal 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 }
|
56
vendor/github.com/go-delve/delve/pkg/proc/native/proc_darwin.h
generated
vendored
Normal file
56
vendor/github.com/go-delve/delve/pkg/proc/native/proc_darwin.h
generated
vendored
Normal 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);
|
505
vendor/github.com/go-delve/delve/pkg/proc/native/proc_linux.go
generated
vendored
Normal file
505
vendor/github.com/go-delve/delve/pkg/proc/native/proc_linux.go
generated
vendored
Normal 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)
|
||||
}
|
495
vendor/github.com/go-delve/delve/pkg/proc/native/proc_windows.go
generated
vendored
Normal file
495
vendor/github.com/go-delve/delve/pkg/proc/native/proc_windows.go
generated
vendored
Normal 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()
|
||||
}
|
30
vendor/github.com/go-delve/delve/pkg/proc/native/ptrace_darwin.go
generated
vendored
Normal file
30
vendor/github.com/go-delve/delve/pkg/proc/native/ptrace_darwin.go
generated
vendored
Normal 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
|
||||
}
|
84
vendor/github.com/go-delve/delve/pkg/proc/native/ptrace_linux.go
generated
vendored
Normal file
84
vendor/github.com/go-delve/delve/pkg/proc/native/ptrace_linux.go
generated
vendored
Normal 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 Developer’s 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(®set.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, ®set)
|
||||
return regset, err
|
||||
}
|
377
vendor/github.com/go-delve/delve/pkg/proc/native/registers_darwin_amd64.go
generated
vendored
Normal file
377
vendor/github.com/go-delve/delve/pkg/proc/native/registers_darwin_amd64.go
generated
vendored
Normal 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 thread’s 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
|
||||
}
|
87
vendor/github.com/go-delve/delve/pkg/proc/native/registers_linux_amd64.go
generated
vendored
Normal file
87
vendor/github.com/go-delve/delve/pkg/proc/native/registers_linux_amd64.go
generated
vendored
Normal 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)(®s)) })
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r := &linutil.AMD64Registers{®s, 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
|
||||
}
|
71
vendor/github.com/go-delve/delve/pkg/proc/native/registers_windows_amd64.go
generated
vendored
Normal file
71
vendor/github.com/go-delve/delve/pkg/proc/native/registers_windows_amd64.go
generated
vendored
Normal 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
|
||||
}
|
119
vendor/github.com/go-delve/delve/pkg/proc/native/syscall_windows.go
generated
vendored
Normal file
119
vendor/github.com/go-delve/delve/pkg/proc/native/syscall_windows.go
generated
vendored
Normal 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
|
24
vendor/github.com/go-delve/delve/pkg/proc/native/syscall_windows_amd64.go
generated
vendored
Normal file
24
vendor/github.com/go-delve/delve/pkg/proc/native/syscall_windows_amd64.go
generated
vendored
Normal 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
|
||||
}
|
174
vendor/github.com/go-delve/delve/pkg/proc/native/threads.go
generated
vendored
Normal file
174
vendor/github.com/go-delve/delve/pkg/proc/native/threads.go
generated
vendored
Normal 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
|
||||
}
|
179
vendor/github.com/go-delve/delve/pkg/proc/native/threads_darwin.c
generated
vendored
Normal file
179
vendor/github.com/go-delve/delve/pkg/proc/native/threads_darwin.c
generated
vendored
Normal 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)®s, &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)®s, 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)®s, &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)®s, 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;
|
||||
}
|
153
vendor/github.com/go-delve/delve/pkg/proc/native/threads_darwin.go
generated
vendored
Normal file
153
vendor/github.com/go-delve/delve/pkg/proc/native/threads_darwin.go
generated
vendored
Normal 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")
|
||||
}
|
43
vendor/github.com/go-delve/delve/pkg/proc/native/threads_darwin.h
generated
vendored
Normal file
43
vendor/github.com/go-delve/delve/pkg/proc/native/threads_darwin.h
generated
vendored
Normal 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);
|
133
vendor/github.com/go-delve/delve/pkg/proc/native/threads_linux.go
generated
vendored
Normal file
133
vendor/github.com/go-delve/delve/pkg/proc/native/threads_linux.go
generated
vendored
Normal 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
|
||||
}
|
159
vendor/github.com/go-delve/delve/pkg/proc/native/threads_windows.go
generated
vendored
Normal file
159
vendor/github.com/go-delve/delve/pkg/proc/native/threads_windows.go
generated
vendored
Normal 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)
|
||||
}
|
181
vendor/github.com/go-delve/delve/pkg/proc/native/zsyscall_windows.go
generated
vendored
Normal file
181
vendor/github.com/go-delve/delve/pkg/proc/native/zsyscall_windows.go
generated
vendored
Normal 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
|
||||
}
|
Reference in New Issue
Block a user