Preliminary implementation of signal handling for x86-64.
This commit is contained in:
parent
08de86c831
commit
ebf7a5d408
|
@ -40,6 +40,7 @@ C_SRCS = \
|
|||
signal_i386.c \
|
||||
signal_powerpc.c \
|
||||
signal_sparc.c \
|
||||
signal_x86_64.c \
|
||||
string.c \
|
||||
sync.c \
|
||||
version.c \
|
||||
|
|
|
@ -0,0 +1,507 @@
|
|||
/*
|
||||
* x86-64 signal handling routines
|
||||
*
|
||||
* Copyright 1999, 2005 Alexandre Julliard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifdef __x86_64__
|
||||
|
||||
#include "config.h"
|
||||
#include "wine/port.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
# include <sys/param.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SIGNAL_H
|
||||
# include <sys/signal.h>
|
||||
#endif
|
||||
|
||||
#define NONAMELESSUNION
|
||||
#include "windef.h"
|
||||
#include "winternl.h"
|
||||
#include "wine/library.h"
|
||||
#include "wine/exception.h"
|
||||
#include "ntdll_misc.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(seh);
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* signal context platform-specific definitions
|
||||
*/
|
||||
#ifdef linux
|
||||
|
||||
typedef struct ucontext SIGCONTEXT;
|
||||
|
||||
# define HANDLER_DEF(name) void name( int __signal, struct siginfo *__siginfo, SIGCONTEXT *__context )
|
||||
# define HANDLER_CONTEXT (__context)
|
||||
|
||||
#define RAX_sig(context) ((context)->uc_mcontext.gregs[REG_RAX])
|
||||
#define RBX_sig(context) ((context)->uc_mcontext.gregs[REG_RBX])
|
||||
#define RCX_sig(context) ((context)->uc_mcontext.gregs[REG_RCX])
|
||||
#define RDX_sig(context) ((context)->uc_mcontext.gregs[REG_RDX])
|
||||
#define RSI_sig(context) ((context)->uc_mcontext.gregs[REG_RSI])
|
||||
#define RDI_sig(context) ((context)->uc_mcontext.gregs[REG_RDI])
|
||||
#define RBP_sig(context) ((context)->uc_mcontext.gregs[REG_RBP])
|
||||
#define R8_sig(context) ((context)->uc_mcontext.gregs[REG_R8])
|
||||
#define R9_sig(context) ((context)->uc_mcontext.gregs[REG_R9])
|
||||
#define R10_sig(context) ((context)->uc_mcontext.gregs[REG_R10])
|
||||
#define R11_sig(context) ((context)->uc_mcontext.gregs[REG_R11])
|
||||
#define R12_sig(context) ((context)->uc_mcontext.gregs[REG_R12])
|
||||
#define R13_sig(context) ((context)->uc_mcontext.gregs[REG_R13])
|
||||
#define R14_sig(context) ((context)->uc_mcontext.gregs[REG_R14])
|
||||
#define R15_sig(context) ((context)->uc_mcontext.gregs[REG_R15])
|
||||
|
||||
#define CS_sig(context) (*((WORD *)&(context)->uc_mcontext.gregs[REG_CSGSFS] + 0))
|
||||
#define GS_sig(context) (*((WORD *)&(context)->uc_mcontext.gregs[REG_CSGSFS] + 1))
|
||||
#define FS_sig(context) (*((WORD *)&(context)->uc_mcontext.gregs[REG_CSGSFS] + 2))
|
||||
|
||||
#define RSP_sig(context) ((context)->uc_mcontext.gregs[REG_RSP])
|
||||
#define RIP_sig(context) ((context)->uc_mcontext.gregs[REG_RIP])
|
||||
#define EFL_sig(context) ((context)->uc_mcontext.gregs[REG_EFL])
|
||||
#define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
|
||||
#define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
|
||||
|
||||
#define FPU_sig(context) ((XMM_SAVE_AREA32 *)((context)->uc_mcontext.fpregs))
|
||||
|
||||
#define FAULT_CODE (__siginfo->si_code)
|
||||
#define FAULT_ADDRESS (__siginfo->si_addr)
|
||||
|
||||
#endif /* linux */
|
||||
|
||||
#define T_UNKNOWN (-1) /* Unknown fault (TRAP_sig not defined) */
|
||||
#define T_DIVIDE 0 /* Division by zero exception */
|
||||
#define T_TRCTRAP 1 /* Single-step exception */
|
||||
#define T_NMI 2 /* NMI interrupt */
|
||||
#define T_BPTFLT 3 /* Breakpoint exception */
|
||||
#define T_OFLOW 4 /* Overflow exception */
|
||||
#define T_BOUND 5 /* Bound range exception */
|
||||
#define T_PRIVINFLT 6 /* Invalid opcode exception */
|
||||
#define T_DNA 7 /* Device not available exception */
|
||||
#define T_DOUBLEFLT 8 /* Double fault exception */
|
||||
#define T_FPOPFLT 9 /* Coprocessor segment overrun */
|
||||
#define T_TSSFLT 10 /* Invalid TSS exception */
|
||||
#define T_SEGNPFLT 11 /* Segment not present exception */
|
||||
#define T_STKFLT 12 /* Stack fault */
|
||||
#define T_PROTFLT 13 /* General protection fault */
|
||||
#define T_PAGEFLT 14 /* Page fault */
|
||||
#define T_RESERVED 15 /* Unknown exception */
|
||||
#define T_ARITHTRAP 16 /* Floating point exception */
|
||||
#define T_ALIGNFLT 17 /* Alignment check exception */
|
||||
#define T_MCHK 18 /* Machine check exception */
|
||||
#define T_CACHEFLT 19 /* Cache flush exception */
|
||||
|
||||
typedef int (*wine_signal_handler)(unsigned int sig);
|
||||
|
||||
static wine_signal_handler handlers[256];
|
||||
|
||||
/***********************************************************************
|
||||
* dispatch_signal
|
||||
*/
|
||||
inline static int dispatch_signal(unsigned int sig)
|
||||
{
|
||||
if (handlers[sig] == NULL) return 0;
|
||||
return handlers[sig](sig);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* save_context
|
||||
*
|
||||
* Set the register values from a sigcontext.
|
||||
*/
|
||||
static void save_context( CONTEXT *context, const SIGCONTEXT *sigcontext )
|
||||
{
|
||||
context->Rax = RAX_sig(sigcontext);
|
||||
context->Rcx = RCX_sig(sigcontext);
|
||||
context->Rdx = RDX_sig(sigcontext);
|
||||
context->Rbx = RBX_sig(sigcontext);
|
||||
context->Rsp = RSP_sig(sigcontext);
|
||||
context->Rbp = RBP_sig(sigcontext);
|
||||
context->Rsi = RSI_sig(sigcontext);
|
||||
context->Rdi = RDI_sig(sigcontext);
|
||||
context->R8 = R8_sig(sigcontext);
|
||||
context->R9 = R9_sig(sigcontext);
|
||||
context->R10 = R10_sig(sigcontext);
|
||||
context->R11 = R11_sig(sigcontext);
|
||||
context->R12 = R12_sig(sigcontext);
|
||||
context->R13 = R13_sig(sigcontext);
|
||||
context->R14 = R14_sig(sigcontext);
|
||||
context->R15 = R15_sig(sigcontext);
|
||||
context->Rip = RIP_sig(sigcontext);
|
||||
context->SegCs = CS_sig(sigcontext);
|
||||
context->SegFs = FS_sig(sigcontext);
|
||||
context->SegGs = GS_sig(sigcontext);
|
||||
context->EFlags = EFL_sig(sigcontext);
|
||||
context->SegDs = 0; /* FIXME */
|
||||
context->SegEs = 0; /* FIXME */
|
||||
context->SegSs = 0; /* FIXME */
|
||||
context->MxCsr = 0; /* FIXME */
|
||||
if (FPU_sig(sigcontext)) context->u.FltSave = *FPU_sig(sigcontext);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* restore_context
|
||||
*
|
||||
* Build a sigcontext from the register values.
|
||||
*/
|
||||
static void restore_context( const CONTEXT *context, SIGCONTEXT *sigcontext )
|
||||
{
|
||||
RAX_sig(sigcontext) = context->Rax;
|
||||
RCX_sig(sigcontext) = context->Rcx;
|
||||
RDX_sig(sigcontext) = context->Rdx;
|
||||
RBX_sig(sigcontext) = context->Rbx;
|
||||
RSP_sig(sigcontext) = context->Rsp;
|
||||
RBP_sig(sigcontext) = context->Rbp;
|
||||
RSI_sig(sigcontext) = context->Rsi;
|
||||
RDI_sig(sigcontext) = context->Rdi;
|
||||
R8_sig(sigcontext) = context->R8;
|
||||
R9_sig(sigcontext) = context->R9;
|
||||
R10_sig(sigcontext) = context->R10;
|
||||
R11_sig(sigcontext) = context->R11;
|
||||
R12_sig(sigcontext) = context->R12;
|
||||
R13_sig(sigcontext) = context->R13;
|
||||
R14_sig(sigcontext) = context->R14;
|
||||
R15_sig(sigcontext) = context->R15;
|
||||
RIP_sig(sigcontext) = context->Rip;
|
||||
CS_sig(sigcontext) = context->SegCs;
|
||||
FS_sig(sigcontext) = context->SegFs;
|
||||
GS_sig(sigcontext) = context->SegGs;
|
||||
EFL_sig(sigcontext) = context->EFlags;
|
||||
if (FPU_sig(sigcontext)) *FPU_sig(sigcontext) = context->u.FltSave;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* segv_handler
|
||||
*
|
||||
* Handler for SIGSEGV and related errors.
|
||||
*/
|
||||
static HANDLER_DEF(segv_handler)
|
||||
{
|
||||
EXCEPTION_RECORD rec;
|
||||
CONTEXT context;
|
||||
|
||||
save_context( &context, HANDLER_CONTEXT );
|
||||
|
||||
rec.ExceptionRecord = NULL;
|
||||
rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
|
||||
rec.ExceptionAddress = (LPVOID)context.Rip;
|
||||
rec.NumberParameters = 0;
|
||||
|
||||
switch(TRAP_sig(HANDLER_CONTEXT))
|
||||
{
|
||||
case T_OFLOW: /* Overflow exception */
|
||||
rec.ExceptionCode = EXCEPTION_INT_OVERFLOW;
|
||||
break;
|
||||
case T_BOUND: /* Bound range exception */
|
||||
rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
|
||||
break;
|
||||
case T_PRIVINFLT: /* Invalid opcode exception */
|
||||
rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
|
||||
break;
|
||||
case T_STKFLT: /* Stack fault */
|
||||
rec.ExceptionCode = EXCEPTION_STACK_OVERFLOW;
|
||||
break;
|
||||
case T_SEGNPFLT: /* Segment not present exception */
|
||||
case T_PROTFLT: /* General protection fault */
|
||||
case T_UNKNOWN: /* Unknown fault code */
|
||||
rec.ExceptionCode = ERROR_sig(HANDLER_CONTEXT) ? EXCEPTION_ACCESS_VIOLATION
|
||||
: EXCEPTION_PRIV_INSTRUCTION;
|
||||
break;
|
||||
case T_PAGEFLT: /* Page fault */
|
||||
rec.ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
|
||||
#ifdef FAULT_ADDRESS
|
||||
rec.NumberParameters = 2;
|
||||
rec.ExceptionInformation[0] = (ERROR_sig(HANDLER_CONTEXT) & 2) != 0;
|
||||
rec.ExceptionInformation[1] = (ULONG_PTR)FAULT_ADDRESS;
|
||||
#endif
|
||||
break;
|
||||
case T_ALIGNFLT: /* Alignment check exception */
|
||||
rec.ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT;
|
||||
break;
|
||||
default:
|
||||
ERR( "Got unexpected trap %ld\n", TRAP_sig(HANDLER_CONTEXT) );
|
||||
/* fall through */
|
||||
case T_NMI: /* NMI interrupt */
|
||||
case T_DNA: /* Device not available exception */
|
||||
case T_DOUBLEFLT: /* Double fault exception */
|
||||
case T_TSSFLT: /* Invalid TSS exception */
|
||||
case T_RESERVED: /* Unknown exception */
|
||||
case T_MCHK: /* Machine check exception */
|
||||
case T_CACHEFLT: /* Cache flush exception */
|
||||
rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
|
||||
break;
|
||||
}
|
||||
|
||||
__regs_RtlRaiseException( &rec, &context );
|
||||
restore_context( &context, HANDLER_CONTEXT );
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* trap_handler
|
||||
*
|
||||
* Handler for SIGTRAP.
|
||||
*/
|
||||
static HANDLER_DEF(trap_handler)
|
||||
{
|
||||
EXCEPTION_RECORD rec;
|
||||
CONTEXT context;
|
||||
|
||||
save_context( &context, HANDLER_CONTEXT );
|
||||
rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
|
||||
rec.ExceptionRecord = NULL;
|
||||
rec.ExceptionAddress = (LPVOID)context.Rip;
|
||||
rec.NumberParameters = 0;
|
||||
|
||||
switch(FAULT_CODE)
|
||||
{
|
||||
case TRAP_TRACE: /* Single-step exception */
|
||||
rec.ExceptionCode = EXCEPTION_SINGLE_STEP;
|
||||
EFL_sig(HANDLER_CONTEXT) &= ~0x100; /* clear single-step flag */
|
||||
break;
|
||||
case TRAP_BRKPT: /* Breakpoint exception */
|
||||
rec.ExceptionAddress = (char *)rec.ExceptionAddress - 1; /* back up over the int3 instruction */
|
||||
/* fall through */
|
||||
default:
|
||||
rec.ExceptionCode = EXCEPTION_BREAKPOINT;
|
||||
break;
|
||||
}
|
||||
|
||||
__regs_RtlRaiseException( &rec, &context );
|
||||
restore_context( &context, HANDLER_CONTEXT );
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* fpe_handler
|
||||
*
|
||||
* Handler for SIGFPE.
|
||||
*/
|
||||
static HANDLER_DEF(fpe_handler)
|
||||
{
|
||||
EXCEPTION_RECORD rec;
|
||||
CONTEXT context;
|
||||
|
||||
save_context( &context, HANDLER_CONTEXT );
|
||||
rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
|
||||
rec.ExceptionRecord = NULL;
|
||||
rec.ExceptionAddress = (LPVOID)context.Rip;
|
||||
rec.NumberParameters = 0;
|
||||
|
||||
switch (FAULT_CODE)
|
||||
{
|
||||
case FPE_FLTSUB:
|
||||
rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
|
||||
break;
|
||||
case FPE_INTDIV:
|
||||
rec.ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO;
|
||||
break;
|
||||
case FPE_INTOVF:
|
||||
rec.ExceptionCode = EXCEPTION_INT_OVERFLOW;
|
||||
break;
|
||||
case FPE_FLTDIV:
|
||||
rec.ExceptionCode = EXCEPTION_FLT_DIVIDE_BY_ZERO;
|
||||
break;
|
||||
case FPE_FLTOVF:
|
||||
rec.ExceptionCode = EXCEPTION_FLT_OVERFLOW;
|
||||
break;
|
||||
case FPE_FLTUND:
|
||||
rec.ExceptionCode = EXCEPTION_FLT_UNDERFLOW;
|
||||
break;
|
||||
case FPE_FLTRES:
|
||||
rec.ExceptionCode = EXCEPTION_FLT_INEXACT_RESULT;
|
||||
break;
|
||||
case FPE_FLTINV:
|
||||
default:
|
||||
rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
|
||||
break;
|
||||
}
|
||||
|
||||
__regs_RtlRaiseException( &rec, &context );
|
||||
restore_context( &context, HANDLER_CONTEXT );
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* int_handler
|
||||
*
|
||||
* Handler for SIGINT.
|
||||
*/
|
||||
static HANDLER_DEF(int_handler)
|
||||
{
|
||||
if (!dispatch_signal(SIGINT))
|
||||
{
|
||||
EXCEPTION_RECORD rec;
|
||||
CONTEXT context;
|
||||
|
||||
save_context( &context, HANDLER_CONTEXT );
|
||||
rec.ExceptionCode = CONTROL_C_EXIT;
|
||||
rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
|
||||
rec.ExceptionRecord = NULL;
|
||||
rec.ExceptionAddress = (LPVOID)context.Rip;
|
||||
rec.NumberParameters = 0;
|
||||
__regs_RtlRaiseException( &rec, &context );
|
||||
restore_context( &context, HANDLER_CONTEXT );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* abrt_handler
|
||||
*
|
||||
* Handler for SIGABRT.
|
||||
*/
|
||||
static HANDLER_DEF(abrt_handler)
|
||||
{
|
||||
EXCEPTION_RECORD rec;
|
||||
CONTEXT context;
|
||||
|
||||
save_context( &context, HANDLER_CONTEXT );
|
||||
rec.ExceptionCode = EXCEPTION_WINE_ASSERTION;
|
||||
rec.ExceptionFlags = EH_NONCONTINUABLE;
|
||||
rec.ExceptionRecord = NULL;
|
||||
rec.ExceptionAddress = (LPVOID)context.Rip;
|
||||
rec.NumberParameters = 0;
|
||||
__regs_RtlRaiseException( &rec, &context ); /* Should never return.. */
|
||||
restore_context( &context, HANDLER_CONTEXT );
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* term_handler
|
||||
*
|
||||
* Handler for SIGTERM.
|
||||
*/
|
||||
static HANDLER_DEF(term_handler)
|
||||
{
|
||||
server_abort_thread(0);
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* usr1_handler
|
||||
*
|
||||
* Handler for SIGUSR1, used to signal a thread that it got suspended.
|
||||
*/
|
||||
static HANDLER_DEF(usr1_handler)
|
||||
{
|
||||
LARGE_INTEGER timeout;
|
||||
|
||||
/* wait with 0 timeout, will only return once the thread is no longer suspended */
|
||||
timeout.QuadPart = 0;
|
||||
NTDLL_wait_for_multiple_objects( 0, NULL, 0, &timeout, 0 );
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* get_signal_stack_total_size
|
||||
*
|
||||
* Retrieve the size to allocate for the signal stack, including the TEB at the bottom.
|
||||
* Must be a power of two.
|
||||
*/
|
||||
size_t get_signal_stack_total_size(void)
|
||||
{
|
||||
assert( sizeof(TEB) <= 2*getpagesize() );
|
||||
return 2*getpagesize(); /* this is just for the TEB, we don't need a signal stack */
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* set_handler
|
||||
*
|
||||
* Set a signal handler
|
||||
*/
|
||||
static int set_handler( int sig, void (*func)() )
|
||||
{
|
||||
struct sigaction sig_act;
|
||||
|
||||
sig_act.sa_sigaction = func;
|
||||
sigemptyset( &sig_act.sa_mask );
|
||||
sigaddset( &sig_act.sa_mask, SIGINT );
|
||||
sigaddset( &sig_act.sa_mask, SIGUSR2 );
|
||||
|
||||
sig_act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
|
||||
return sigaction( sig, &sig_act, NULL );
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* __wine_set_signal_handler (NTDLL.@)
|
||||
*/
|
||||
int __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh)
|
||||
{
|
||||
if (sig > sizeof(handlers) / sizeof(handlers[0])) return -1;
|
||||
if (handlers[sig] != NULL) return -2;
|
||||
handlers[sig] = wsh;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* SIGNAL_Init
|
||||
*/
|
||||
BOOL SIGNAL_Init(void)
|
||||
{
|
||||
if (set_handler( SIGINT, (void (*)())int_handler ) == -1) goto error;
|
||||
if (set_handler( SIGFPE, (void (*)())fpe_handler ) == -1) goto error;
|
||||
if (set_handler( SIGSEGV, (void (*)())segv_handler ) == -1) goto error;
|
||||
if (set_handler( SIGILL, (void (*)())segv_handler ) == -1) goto error;
|
||||
if (set_handler( SIGABRT, (void (*)())abrt_handler ) == -1) goto error;
|
||||
if (set_handler( SIGTERM, (void (*)())term_handler ) == -1) goto error;
|
||||
if (set_handler( SIGUSR1, (void (*)())usr1_handler ) == -1) goto error;
|
||||
#ifdef SIGBUS
|
||||
if (set_handler( SIGBUS, (void (*)())segv_handler ) == -1) goto error;
|
||||
#endif
|
||||
#ifdef SIGTRAP
|
||||
if (set_handler( SIGTRAP, (void (*)())trap_handler ) == -1) goto error;
|
||||
#endif
|
||||
return TRUE;
|
||||
|
||||
error:
|
||||
perror("sigaction");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* __wine_enter_vm86 (NTDLL.@)
|
||||
*/
|
||||
void __wine_enter_vm86( CONTEXT *context )
|
||||
{
|
||||
MESSAGE("vm86 mode not supported on this platform\n");
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* DbgBreakPoint (NTDLL.@)
|
||||
*/
|
||||
__ASM_GLOBAL_FUNC( DbgBreakPoint, "int $3; ret");
|
||||
|
||||
/**********************************************************************
|
||||
* DbgUserBreakPoint (NTDLL.@)
|
||||
*/
|
||||
__ASM_GLOBAL_FUNC( DbgUserBreakPoint, "int $3; ret");
|
||||
|
||||
#endif /* __x86_64__ */
|
Loading…
Reference in New Issue