Added specific routines for OUTPUT_DEBUG_STRING and EXCEPTION debug events.
Generate a breakpoint event on process attach. Misc cleanups in request handling.
This commit is contained in:
parent
ebd01a94aa
commit
ea0d028a0b
|
@ -13,9 +13,10 @@
|
|||
#include "wine/exception.h"
|
||||
#include "stackframe.h"
|
||||
#include "miscemu.h"
|
||||
#include "server.h"
|
||||
#include "debugtools.h"
|
||||
|
||||
DEFAULT_DEBUG_CHANNEL(seh)
|
||||
DEFAULT_DEBUG_CHANNEL(seh);
|
||||
|
||||
/* Exception record for handling exceptions happening inside exception handlers */
|
||||
typedef struct
|
||||
|
@ -84,6 +85,22 @@ static DWORD EXC_CallHandler( EXCEPTION_RECORD *record, EXCEPTION_FRAME *frame,
|
|||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* EXC_SendEvent
|
||||
*
|
||||
* Send an EXCEPTION_DEBUG_EVENT event to the debugger.
|
||||
*/
|
||||
static inline int send_debug_event( EXCEPTION_RECORD *rec, int first_chance, CONTEXT *context )
|
||||
{
|
||||
struct exception_event_request *req = get_req_buffer();
|
||||
req->record = *rec;
|
||||
req->first = first_chance;
|
||||
req->context = *context;
|
||||
if (!server_call_noerr( REQ_EXCEPTION_EVENT )) *context = req->context;
|
||||
return req->status;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* EXC_DefaultHandling
|
||||
*
|
||||
|
@ -91,8 +108,7 @@ static DWORD EXC_CallHandler( EXCEPTION_RECORD *record, EXCEPTION_FRAME *frame,
|
|||
*/
|
||||
static void EXC_DefaultHandling( EXCEPTION_RECORD *rec, CONTEXT *context )
|
||||
{
|
||||
if (DEBUG_SendExceptionEvent( rec, FALSE, context ) == DBG_CONTINUE)
|
||||
return; /* continue execution */
|
||||
if (send_debug_event( rec, FALSE, context ) == DBG_CONTINUE) return; /* continue execution */
|
||||
|
||||
if (rec->ExceptionFlags & EH_STACK_INVALID)
|
||||
ERR("Exception frame is not in stack limits => unable to dispatch exception.\n");
|
||||
|
@ -117,8 +133,7 @@ void WINAPI EXC_RtlRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context )
|
|||
|
||||
TRACE( "code=%lx flags=%lx\n", rec->ExceptionCode, rec->ExceptionFlags );
|
||||
|
||||
if (DEBUG_SendExceptionEvent( rec, TRUE, context ) == DBG_CONTINUE)
|
||||
return; /* continue execution */
|
||||
if (send_debug_event( rec, TRUE, context ) == DBG_CONTINUE) return; /* continue execution */
|
||||
|
||||
frame = NtCurrentTeb()->except;
|
||||
nested_frame = NULL;
|
||||
|
|
|
@ -31,14 +31,8 @@ typedef WCHAR path_t[MAX_PATH+1];
|
|||
/* definitions of the event data depending on the event code */
|
||||
struct debug_event_exception
|
||||
{
|
||||
int code; /* exception code */
|
||||
int flags; /* exception flags */
|
||||
void *record; /* exception record ptr */
|
||||
void *addr; /* exception address */
|
||||
int nb_params; /* exceptions parameters */
|
||||
int params[15];
|
||||
int first_chance; /* first chance to handle it? */
|
||||
CONTEXT context; /* thread context */
|
||||
EXCEPTION_RECORD record; /* exception record */
|
||||
int first; /* first chance exception? */
|
||||
};
|
||||
struct debug_event_create_thread
|
||||
{
|
||||
|
@ -813,11 +807,22 @@ struct wait_debug_event_request
|
|||
};
|
||||
|
||||
|
||||
/* Send a debug event */
|
||||
struct send_debug_event_request
|
||||
/* Send an exception event */
|
||||
struct exception_event_request
|
||||
{
|
||||
OUT int status; /* event continuation status */
|
||||
IN debug_event_t event; /* debug event data */
|
||||
IN EXCEPTION_RECORD record; /* exception record */
|
||||
IN int first; /* first chance exception? */
|
||||
IN CONTEXT context; /* thread context */
|
||||
OUT int status; /* event continuation status */
|
||||
};
|
||||
|
||||
|
||||
/* Send an output string to the debugger */
|
||||
struct output_debug_string_request
|
||||
{
|
||||
IN void* string; /* string to display (in debugged process address space) */
|
||||
IN int unicode; /* is it Unicode? */
|
||||
IN int length; /* string length */
|
||||
};
|
||||
|
||||
|
||||
|
@ -1164,7 +1169,8 @@ enum request
|
|||
REQ_CREATE_SNAPSHOT,
|
||||
REQ_NEXT_PROCESS,
|
||||
REQ_WAIT_DEBUG_EVENT,
|
||||
REQ_SEND_DEBUG_EVENT,
|
||||
REQ_EXCEPTION_EVENT,
|
||||
REQ_OUTPUT_DEBUG_STRING,
|
||||
REQ_CONTINUE_DEBUG_EVENT,
|
||||
REQ_DEBUG_PROCESS,
|
||||
REQ_READ_PROCESS_MEMORY,
|
||||
|
@ -1196,7 +1202,7 @@ enum request
|
|||
REQ_NB_REQUESTS
|
||||
};
|
||||
|
||||
#define SERVER_PROTOCOL_VERSION 2
|
||||
#define SERVER_PROTOCOL_VERSION 3
|
||||
|
||||
/* ### make_requests end ### */
|
||||
/* Everything above this line is generated automatically by tools/make_requests */
|
||||
|
|
|
@ -7,39 +7,12 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "winerror.h"
|
||||
#include "process.h"
|
||||
#include "server.h"
|
||||
#include "debugtools.h"
|
||||
|
||||
DEFAULT_DEBUG_CHANNEL(debugstr);
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* DEBUG_SendExceptionEvent
|
||||
*
|
||||
* Send an EXCEPTION_DEBUG_EVENT event to the current process debugger.
|
||||
*/
|
||||
DWORD DEBUG_SendExceptionEvent( EXCEPTION_RECORD *rec, BOOL first_chance, CONTEXT *context )
|
||||
{
|
||||
int i;
|
||||
struct send_debug_event_request *req = get_req_buffer();
|
||||
|
||||
req->event.code = EXCEPTION_DEBUG_EVENT;
|
||||
req->event.info.exception.code = rec->ExceptionCode;
|
||||
req->event.info.exception.flags = rec->ExceptionFlags;
|
||||
req->event.info.exception.record = rec->ExceptionRecord;
|
||||
req->event.info.exception.addr = rec->ExceptionAddress;
|
||||
req->event.info.exception.nb_params = rec->NumberParameters;
|
||||
req->event.info.exception.first_chance = first_chance;
|
||||
req->event.info.exception.context = *context;
|
||||
for (i = 0; i < req->event.info.exception.nb_params; i++)
|
||||
req->event.info.exception.params[i] = rec->ExceptionInformation[i];
|
||||
if (!server_call_noerr( REQ_SEND_DEBUG_EVENT ))
|
||||
*context = req->event.info.exception.context;
|
||||
return req->status;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WaitForDebugEvent (KERNEL32.720)
|
||||
*
|
||||
|
@ -54,7 +27,6 @@ DWORD DEBUG_SendExceptionEvent( EXCEPTION_RECORD *rec, BOOL first_chance, CONTEX
|
|||
BOOL WINAPI WaitForDebugEvent( LPDEBUG_EVENT event, DWORD timeout )
|
||||
{
|
||||
struct wait_debug_event_request *req = get_req_buffer();
|
||||
int i;
|
||||
|
||||
req->timeout = timeout;
|
||||
if (server_call( REQ_WAIT_DEBUG_EVENT )) return FALSE;
|
||||
|
@ -70,14 +42,8 @@ BOOL WINAPI WaitForDebugEvent( LPDEBUG_EVENT event, DWORD timeout )
|
|||
SetLastError( ERROR_SEM_TIMEOUT );
|
||||
return FALSE;
|
||||
case EXCEPTION_DEBUG_EVENT:
|
||||
event->u.Exception.ExceptionRecord.ExceptionCode = req->event.info.exception.code;
|
||||
event->u.Exception.ExceptionRecord.ExceptionFlags = req->event.info.exception.flags;
|
||||
event->u.Exception.ExceptionRecord.ExceptionRecord = req->event.info.exception.record;
|
||||
event->u.Exception.ExceptionRecord.ExceptionAddress = req->event.info.exception.addr;
|
||||
event->u.Exception.ExceptionRecord.NumberParameters = req->event.info.exception.nb_params;
|
||||
for (i = 0; i < req->event.info.exception.nb_params; i++)
|
||||
event->u.Exception.ExceptionRecord.ExceptionInformation[i] = req->event.info.exception.params[i];
|
||||
event->u.Exception.dwFirstChance = req->event.info.exception.first_chance;
|
||||
event->u.Exception.ExceptionRecord = req->event.info.exception.record;
|
||||
event->u.Exception.dwFirstChance = req->event.info.exception.first;
|
||||
break;
|
||||
case CREATE_THREAD_DEBUG_EVENT:
|
||||
event->u.CreateThread.hThread = req->event.info.create_thread.handle;
|
||||
|
@ -158,12 +124,11 @@ BOOL WINAPI DebugActiveProcess( DWORD pid )
|
|||
*/
|
||||
void WINAPI OutputDebugStringA( LPCSTR str )
|
||||
{
|
||||
struct send_debug_event_request *req = get_req_buffer();
|
||||
req->event.code = OUTPUT_DEBUG_STRING_EVENT;
|
||||
req->event.info.output_string.string = (void *)str;
|
||||
req->event.info.output_string.unicode = 0;
|
||||
req->event.info.output_string.length = strlen(str) + 1;
|
||||
server_call_noerr( REQ_SEND_DEBUG_EVENT );
|
||||
struct output_debug_string_request *req = get_req_buffer();
|
||||
req->string = (void *)str;
|
||||
req->unicode = 0;
|
||||
req->length = strlen(str) + 1;
|
||||
server_call_noerr( REQ_OUTPUT_DEBUG_STRING );
|
||||
TRACE("%s\n", str);
|
||||
}
|
||||
|
||||
|
@ -173,12 +138,11 @@ void WINAPI OutputDebugStringA( LPCSTR str )
|
|||
*/
|
||||
void WINAPI OutputDebugStringW( LPCWSTR str )
|
||||
{
|
||||
struct send_debug_event_request *req = get_req_buffer();
|
||||
req->event.code = OUTPUT_DEBUG_STRING_EVENT;
|
||||
req->event.info.output_string.string = (void *)str;
|
||||
req->event.info.output_string.unicode = 1;
|
||||
req->event.info.output_string.length = (lstrlenW(str) + 1) * sizeof(WCHAR);
|
||||
server_call_noerr( REQ_SEND_DEBUG_EVENT );
|
||||
struct output_debug_string_request *req = get_req_buffer();
|
||||
req->string = (void *)str;
|
||||
req->unicode = 1;
|
||||
req->length = (lstrlenW(str) + 1) * sizeof(WCHAR);
|
||||
server_call_noerr( REQ_OUTPUT_DEBUG_STRING );
|
||||
TRACE("%s\n", debugstr_w(str));
|
||||
}
|
||||
|
||||
|
|
|
@ -457,13 +457,12 @@ static void copy_context( CONTEXT *to, CONTEXT *from, int flags )
|
|||
DECL_HANDLER(get_thread_context)
|
||||
{
|
||||
struct thread *thread;
|
||||
CONTEXT *context;
|
||||
|
||||
if ((thread = get_thread_from_handle( req->handle, THREAD_GET_CONTEXT )))
|
||||
{
|
||||
if ((context = get_debug_context( thread ))) /* thread is inside an exception event */
|
||||
if (thread->context) /* thread is inside an exception event */
|
||||
{
|
||||
copy_context( &req->context, context, req->flags );
|
||||
copy_context( &req->context, thread->context, req->flags );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -481,13 +480,12 @@ DECL_HANDLER(get_thread_context)
|
|||
DECL_HANDLER(set_thread_context)
|
||||
{
|
||||
struct thread *thread;
|
||||
CONTEXT *context;
|
||||
|
||||
if ((thread = get_thread_from_handle( req->handle, THREAD_SET_CONTEXT )))
|
||||
{
|
||||
if ((context = get_debug_context( thread ))) /* thread is inside an exception event */
|
||||
if (thread->context) /* thread is inside an exception event */
|
||||
{
|
||||
copy_context( context, &req->context, req->flags );
|
||||
copy_context( thread->context, &req->context, req->flags );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -83,93 +83,132 @@ static const struct object_ops debug_ctx_ops =
|
|||
};
|
||||
|
||||
|
||||
/* initialise the fields that do not need to be filled by the client */
|
||||
static int fill_debug_event( struct debug_event *event, void *arg )
|
||||
/* routines to build an event according to its type */
|
||||
|
||||
static int fill_exception_event( struct debug_event *event, void *arg )
|
||||
{
|
||||
struct process *debugger = event->debugger->process;
|
||||
struct process *process;
|
||||
struct thread *thread;
|
||||
struct process_dll *dll;
|
||||
int handle;
|
||||
|
||||
/* some events need special handling */
|
||||
switch(event->data.code)
|
||||
{
|
||||
case CREATE_THREAD_DEBUG_EVENT:
|
||||
thread = arg;
|
||||
/* documented: THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME */
|
||||
if ((handle = alloc_handle( debugger, thread, THREAD_ALL_ACCESS, FALSE )) == -1)
|
||||
return 0;
|
||||
event->data.info.create_thread.handle = handle;
|
||||
event->data.info.create_thread.teb = thread->teb;
|
||||
event->data.info.create_thread.start = thread->entry;
|
||||
break;
|
||||
case CREATE_PROCESS_DEBUG_EVENT:
|
||||
process = arg;
|
||||
thread = process->thread_list;
|
||||
/* documented: PROCESS_VM_READ | PROCESS_VM_WRITE */
|
||||
if ((handle = alloc_handle( debugger, process, PROCESS_ALL_ACCESS, FALSE )) == -1)
|
||||
return 0;
|
||||
event->data.info.create_process.process = handle;
|
||||
|
||||
/* documented: THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME */
|
||||
if ((handle = alloc_handle( debugger, thread, THREAD_ALL_ACCESS, FALSE )) == -1)
|
||||
{
|
||||
close_handle( debugger, event->data.info.create_process.process );
|
||||
return 0;
|
||||
}
|
||||
event->data.info.create_process.thread = handle;
|
||||
|
||||
handle = -1;
|
||||
if (process->exe.file &&
|
||||
/* the doc says write access too, but this doesn't seem a good idea */
|
||||
((handle = alloc_handle( debugger, process->exe.file, GENERIC_READ, FALSE )) == -1))
|
||||
{
|
||||
close_handle( debugger, event->data.info.create_process.process );
|
||||
close_handle( debugger, event->data.info.create_process.thread );
|
||||
return 0;
|
||||
}
|
||||
event->data.info.create_process.file = handle;
|
||||
event->data.info.create_process.teb = thread->teb;
|
||||
event->data.info.create_process.base = process->exe.base;
|
||||
event->data.info.create_process.start = thread->entry;
|
||||
event->data.info.create_process.dbg_offset = process->exe.dbg_offset;
|
||||
event->data.info.create_process.dbg_size = process->exe.dbg_size;
|
||||
event->data.info.create_process.name = 0;
|
||||
event->data.info.create_process.unicode = 0;
|
||||
break;
|
||||
case LOAD_DLL_DEBUG_EVENT:
|
||||
dll = arg;
|
||||
handle = -1;
|
||||
if (dll->file &&
|
||||
(handle = alloc_handle( debugger, dll->file, GENERIC_READ, FALSE )) == -1)
|
||||
return 0;
|
||||
event->data.info.load_dll.handle = handle;
|
||||
event->data.info.load_dll.base = dll->base;
|
||||
event->data.info.load_dll.dbg_offset = dll->dbg_offset;
|
||||
event->data.info.load_dll.dbg_size = dll->dbg_size;
|
||||
event->data.info.load_dll.name = dll->name;
|
||||
event->data.info.load_dll.unicode = 0;
|
||||
break;
|
||||
case EXIT_PROCESS_DEBUG_EVENT:
|
||||
process = arg;
|
||||
event->data.info.exit.exit_code = process->exit_code;
|
||||
break;
|
||||
case EXIT_THREAD_DEBUG_EVENT:
|
||||
thread = arg;
|
||||
event->data.info.exit.exit_code = thread->exit_code;
|
||||
break;
|
||||
case UNLOAD_DLL_DEBUG_EVENT:
|
||||
event->data.info.unload_dll.base = arg;
|
||||
break;
|
||||
case EXCEPTION_DEBUG_EVENT:
|
||||
case OUTPUT_DEBUG_STRING_EVENT:
|
||||
case RIP_EVENT:
|
||||
break;
|
||||
}
|
||||
memcpy( &event->data.info.exception, arg, sizeof(event->data.info.exception) );
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int fill_create_thread_event( struct debug_event *event, void *arg )
|
||||
{
|
||||
struct process *debugger = event->debugger->process;
|
||||
struct thread *thread = arg;
|
||||
int handle;
|
||||
|
||||
/* documented: THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME */
|
||||
if ((handle = alloc_handle( debugger, thread, THREAD_ALL_ACCESS, FALSE )) == -1)
|
||||
return 0;
|
||||
event->data.info.create_thread.handle = handle;
|
||||
event->data.info.create_thread.teb = thread->teb;
|
||||
event->data.info.create_thread.start = thread->entry;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int fill_create_process_event( struct debug_event *event, void *arg )
|
||||
{
|
||||
struct process *debugger = event->debugger->process;
|
||||
struct process *process = arg;
|
||||
struct thread *thread = process->thread_list;
|
||||
int handle;
|
||||
|
||||
/* documented: PROCESS_VM_READ | PROCESS_VM_WRITE */
|
||||
if ((handle = alloc_handle( debugger, process, PROCESS_ALL_ACCESS, FALSE )) == -1)
|
||||
return 0;
|
||||
event->data.info.create_process.process = handle;
|
||||
|
||||
/* documented: THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME */
|
||||
if ((handle = alloc_handle( debugger, thread, THREAD_ALL_ACCESS, FALSE )) == -1)
|
||||
{
|
||||
close_handle( debugger, event->data.info.create_process.process );
|
||||
return 0;
|
||||
}
|
||||
event->data.info.create_process.thread = handle;
|
||||
|
||||
handle = -1;
|
||||
if (process->exe.file &&
|
||||
/* the doc says write access too, but this doesn't seem a good idea */
|
||||
((handle = alloc_handle( debugger, process->exe.file, GENERIC_READ, FALSE )) == -1))
|
||||
{
|
||||
close_handle( debugger, event->data.info.create_process.process );
|
||||
close_handle( debugger, event->data.info.create_process.thread );
|
||||
return 0;
|
||||
}
|
||||
event->data.info.create_process.file = handle;
|
||||
event->data.info.create_process.teb = thread->teb;
|
||||
event->data.info.create_process.base = process->exe.base;
|
||||
event->data.info.create_process.start = thread->entry;
|
||||
event->data.info.create_process.dbg_offset = process->exe.dbg_offset;
|
||||
event->data.info.create_process.dbg_size = process->exe.dbg_size;
|
||||
event->data.info.create_process.name = 0;
|
||||
event->data.info.create_process.unicode = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int fill_exit_thread_event( struct debug_event *event, void *arg )
|
||||
{
|
||||
struct thread *thread = arg;
|
||||
event->data.info.exit.exit_code = thread->exit_code;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int fill_exit_process_event( struct debug_event *event, void *arg )
|
||||
{
|
||||
struct process *process = arg;
|
||||
event->data.info.exit.exit_code = process->exit_code;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int fill_load_dll_event( struct debug_event *event, void *arg )
|
||||
{
|
||||
struct process *debugger = event->debugger->process;
|
||||
struct process_dll *dll = arg;
|
||||
int handle = -1;
|
||||
|
||||
if (dll->file && (handle = alloc_handle( debugger, dll->file, GENERIC_READ, FALSE )) == -1)
|
||||
return 0;
|
||||
event->data.info.load_dll.handle = handle;
|
||||
event->data.info.load_dll.base = dll->base;
|
||||
event->data.info.load_dll.dbg_offset = dll->dbg_offset;
|
||||
event->data.info.load_dll.dbg_size = dll->dbg_size;
|
||||
event->data.info.load_dll.name = dll->name;
|
||||
event->data.info.load_dll.unicode = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int fill_unload_dll_event( struct debug_event *event, void *arg )
|
||||
{
|
||||
event->data.info.unload_dll.base = arg;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int fill_output_debug_string_event( struct debug_event *event, void *arg )
|
||||
{
|
||||
struct output_debug_string_request *req = arg;
|
||||
event->data.info.output_string.string = req->string;
|
||||
event->data.info.output_string.unicode = req->unicode;
|
||||
event->data.info.output_string.length = req->length;
|
||||
return 1;
|
||||
}
|
||||
|
||||
typedef int (*fill_event_func)( struct debug_event *event, void *arg );
|
||||
|
||||
#define NB_DEBUG_EVENTS OUTPUT_DEBUG_STRING_EVENT /* RIP_EVENT not supported */
|
||||
|
||||
static const fill_event_func fill_debug_event[NB_DEBUG_EVENTS] =
|
||||
{
|
||||
fill_exception_event, /* EXCEPTION_DEBUG_EVENT */
|
||||
fill_create_thread_event, /* CREATE_THREAD_DEBUG_EVENT */
|
||||
fill_create_process_event, /* CREATE_PROCESS_DEBUG_EVENT */
|
||||
fill_exit_thread_event, /* EXIT_THREAD_DEBUG_EVENT */
|
||||
fill_exit_process_event, /* EXIT_PROCESS_DEBUG_EVENT */
|
||||
fill_load_dll_event, /* LOAD_DLL_DEBUG_EVENT */
|
||||
fill_unload_dll_event, /* UNLOAD_DLL_DEBUG_EVENT */
|
||||
fill_output_debug_string_event /* OUTPUT_DEBUG_STRING_EVENT */
|
||||
};
|
||||
|
||||
|
||||
/* unlink the first event from the queue */
|
||||
static void unlink_event( struct debug_ctx *debug_ctx, struct debug_event *event )
|
||||
{
|
||||
|
@ -228,18 +267,13 @@ static void build_wait_debug_reply( struct thread *thread, struct object *obj, i
|
|||
}
|
||||
|
||||
/* build a reply for the send_event request */
|
||||
static void build_send_event_reply( struct thread *thread, struct object *obj, int signaled )
|
||||
static void build_exception_event_reply( struct thread *thread, struct object *obj, int signaled )
|
||||
{
|
||||
struct send_debug_event_request *req = get_req_ptr( thread );
|
||||
struct exception_event_request *req = get_req_ptr( thread );
|
||||
struct debug_event *event = (struct debug_event *)obj;
|
||||
assert( obj->ops == &debug_event_ops );
|
||||
|
||||
req->status = event->status;
|
||||
/* copy the context into the reply */
|
||||
if (event->data.code == EXCEPTION_DEBUG_EVENT)
|
||||
memcpy( &req->event.info.exception.context,
|
||||
&event->data.info.exception.context,
|
||||
sizeof(req->event.info.exception.context) );
|
||||
thread->context = NULL;
|
||||
}
|
||||
|
||||
static void debug_event_dump( struct object *obj, int verbose )
|
||||
|
@ -363,28 +397,27 @@ static int continue_debug_event( struct process *process, struct thread *thread,
|
|||
}
|
||||
|
||||
/* queue a debug event for a debugger */
|
||||
static struct debug_event *queue_debug_event( struct thread *thread, int code, void *arg,
|
||||
debug_event_t *data )
|
||||
static struct debug_event *queue_debug_event( struct thread *thread, int code, void *arg )
|
||||
{
|
||||
struct thread *debugger = thread->process->debugger;
|
||||
struct debug_ctx *debug_ctx = debugger->debug_ctx;
|
||||
struct debug_event *event;
|
||||
|
||||
assert( code > 0 && code <= NB_DEBUG_EVENTS );
|
||||
assert( debug_ctx );
|
||||
/* cannot queue a debug event for myself */
|
||||
assert( debugger->process != thread->process );
|
||||
|
||||
/* build the event */
|
||||
if (!(event = alloc_object( &debug_event_ops, -1 ))) return NULL;
|
||||
event->next = NULL;
|
||||
event->prev = NULL;
|
||||
event->state = EVENT_QUEUED;
|
||||
event->sender = (struct thread *)grab_object( thread );
|
||||
event->debugger = (struct thread *)grab_object( debugger );
|
||||
if (data) memcpy( &event->data, data, sizeof(event->data) );
|
||||
event->next = NULL;
|
||||
event->prev = NULL;
|
||||
event->state = EVENT_QUEUED;
|
||||
event->sender = (struct thread *)grab_object( thread );
|
||||
event->debugger = (struct thread *)grab_object( debugger );
|
||||
event->data.code = code;
|
||||
|
||||
if (!fill_debug_event( event, arg ))
|
||||
if (!fill_debug_event[code-1]( event, arg ))
|
||||
{
|
||||
event->data.code = -1; /* make sure we don't attempt to close handles */
|
||||
release_object( event );
|
||||
|
@ -401,11 +434,43 @@ void generate_debug_event( struct thread *thread, int code, void *arg )
|
|||
{
|
||||
if (thread->process->debugger)
|
||||
{
|
||||
struct debug_event *event = queue_debug_event( thread, code, arg, NULL );
|
||||
struct debug_event *event = queue_debug_event( thread, code, arg );
|
||||
if (event) release_object( event );
|
||||
}
|
||||
}
|
||||
|
||||
/* attach a process to a debugger thread and suspend it */
|
||||
static int debugger_attach( struct process *process, struct thread *debugger )
|
||||
{
|
||||
struct thread *thread;
|
||||
|
||||
if (process->debugger) goto error; /* already being debugged */
|
||||
if (process->init_event) goto error; /* still starting up */
|
||||
|
||||
/* make sure we don't create a debugging loop */
|
||||
for (thread = debugger; thread; thread = thread->process->debugger)
|
||||
if (thread->process == process) goto error;
|
||||
|
||||
suspend_process( process );
|
||||
|
||||
/* we must have been able to attach all threads */
|
||||
for (thread = process->thread_list; thread; thread = thread->proc_next)
|
||||
if (!thread->attached)
|
||||
{
|
||||
fprintf( stderr, "%p not attached\n", thread );
|
||||
resume_process( process );
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (set_process_debugger( process, debugger )) return 1;
|
||||
resume_process( process );
|
||||
return 0;
|
||||
|
||||
error:
|
||||
set_error( STATUS_ACCESS_DENIED );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* generate all startup events of a given process */
|
||||
void generate_startup_debug_events( struct process *process )
|
||||
{
|
||||
|
@ -426,40 +491,12 @@ void generate_startup_debug_events( struct process *process )
|
|||
}
|
||||
}
|
||||
|
||||
/* return a pointer to the context in case the thread is inside an exception event */
|
||||
CONTEXT *get_debug_context( struct thread *thread )
|
||||
{
|
||||
struct debug_event *event;
|
||||
struct thread *debugger = thread->process->debugger;
|
||||
|
||||
if (!debugger) return NULL; /* not being debugged */
|
||||
assert( debugger->debug_ctx );
|
||||
|
||||
/* find the exception event in the debugger's queue */
|
||||
for (event = debugger->debug_ctx->event_head; event; event = event->next)
|
||||
if (event->sender == thread && (event->data.code == EXCEPTION_DEBUG_EVENT))
|
||||
return &event->data.info.exception.context;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* attach a process to a debugger thread */
|
||||
int debugger_attach( struct process *process, struct thread *debugger )
|
||||
/* set the debugger of a given process */
|
||||
int set_process_debugger( struct process *process, struct thread *debugger )
|
||||
{
|
||||
struct debug_ctx *debug_ctx;
|
||||
struct thread *thread;
|
||||
|
||||
if (process->debugger) /* already being debugged */
|
||||
{
|
||||
set_error( STATUS_ACCESS_DENIED );
|
||||
return 0;
|
||||
}
|
||||
/* make sure we don't create a debugging loop */
|
||||
for (thread = debugger; thread; thread = thread->process->debugger)
|
||||
if (thread->process == process)
|
||||
{
|
||||
set_error( STATUS_ACCESS_DENIED );
|
||||
return 0;
|
||||
}
|
||||
assert( !process->debugger );
|
||||
|
||||
if (!debugger->debug_ctx) /* need to allocate a context */
|
||||
{
|
||||
|
@ -515,34 +552,54 @@ DECL_HANDLER(continue_debug_event)
|
|||
/* Start debugging an existing process */
|
||||
DECL_HANDLER(debug_process)
|
||||
{
|
||||
struct debug_event_exception data;
|
||||
struct debug_event *event;
|
||||
struct process *process = get_process_from_id( req->pid );
|
||||
if (!process) return;
|
||||
|
||||
if (debugger_attach( process, current ))
|
||||
{
|
||||
generate_startup_debug_events( process );
|
||||
/* FIXME: breakpoint exception event */
|
||||
resume_process( process );
|
||||
|
||||
data.record.ExceptionCode = EXCEPTION_BREAKPOINT;
|
||||
data.record.ExceptionFlags = EXCEPTION_CONTINUABLE;
|
||||
data.record.ExceptionRecord = NULL;
|
||||
data.record.ExceptionAddress = process->thread_list->entry; /* FIXME */
|
||||
data.record.NumberParameters = 0;
|
||||
data.first = 1;
|
||||
if ((event = queue_debug_event( process->thread_list, EXCEPTION_DEBUG_EVENT, &data )))
|
||||
release_object( event );
|
||||
}
|
||||
release_object( process );
|
||||
}
|
||||
|
||||
/* Send a debug event */
|
||||
DECL_HANDLER(send_debug_event)
|
||||
/* send an exception event */
|
||||
DECL_HANDLER(exception_event)
|
||||
{
|
||||
struct debug_event *event;
|
||||
int code = req->event.code;
|
||||
if (current->process->debugger)
|
||||
{
|
||||
struct debug_event_exception data;
|
||||
struct debug_event *event;
|
||||
|
||||
if ((code <= 0) || (code > RIP_EVENT))
|
||||
{
|
||||
fatal_protocol_error( current, "send_debug_event: bad code %d\n", code );
|
||||
return;
|
||||
}
|
||||
req->status = 0;
|
||||
if (current->process->debugger && ((event = queue_debug_event( current, code,
|
||||
NULL, &req->event ))))
|
||||
{
|
||||
/* wait for continue_debug_event */
|
||||
struct object *obj = &event->obj;
|
||||
sleep_on( 1, &obj, 0, -1, build_send_event_reply );
|
||||
release_object( event );
|
||||
data.record = req->record;
|
||||
data.first = req->first;
|
||||
if ((event = queue_debug_event( current, EXCEPTION_DEBUG_EVENT, &data )))
|
||||
{
|
||||
struct object *obj = &event->obj;
|
||||
current->context = &req->context;
|
||||
sleep_on( 1, &obj, 0, -1, build_exception_event_reply );
|
||||
release_object( event );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* send an output string to the debugger */
|
||||
DECL_HANDLER(output_debug_string)
|
||||
{
|
||||
if (current->process->debugger)
|
||||
{
|
||||
struct debug_event *event = queue_debug_event( current, OUTPUT_DEBUG_STRING_EVENT, req );
|
||||
if (event) release_object( event );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -468,15 +468,17 @@ DECL_HANDLER(alloc_file_handle)
|
|||
struct file *file;
|
||||
|
||||
req->handle = -1;
|
||||
if ((fd = dup(fd)) != -1)
|
||||
if (current->pass_fd != -1)
|
||||
{
|
||||
if ((file = create_file_for_fd( fd, req->access, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 )))
|
||||
if ((file = create_file_for_fd( current->pass_fd, req->access,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, 0 )))
|
||||
{
|
||||
req->handle = alloc_handle( current->process, file, req->access, 0 );
|
||||
release_object( file );
|
||||
}
|
||||
current->pass_fd = -1;
|
||||
}
|
||||
else file_set_error();
|
||||
else set_error( STATUS_INVALID_PARAMETER );
|
||||
}
|
||||
|
||||
/* get a Unix fd to read from a file */
|
||||
|
|
|
@ -60,7 +60,6 @@ static void sigterm_handler()
|
|||
/* initialize signal handling */
|
||||
static void signal_init(void)
|
||||
{
|
||||
#if 0
|
||||
if (!debug_level)
|
||||
{
|
||||
switch(fork())
|
||||
|
@ -74,7 +73,6 @@ static void signal_init(void)
|
|||
exit(0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
signal( SIGPIPE, SIG_IGN );
|
||||
signal( SIGHUP, sigterm_handler );
|
||||
signal( SIGINT, sigterm_handler );
|
||||
|
|
|
@ -153,11 +153,10 @@ extern int free_console( struct process *process );
|
|||
|
||||
/* debugger functions */
|
||||
|
||||
extern int debugger_attach( struct process *process, struct thread *debugger );
|
||||
extern int set_process_debugger( struct process *process, struct thread *debugger );
|
||||
extern void generate_debug_event( struct thread *thread, int code, void *arg );
|
||||
extern void generate_startup_debug_events( struct process *process );
|
||||
extern void debug_exit_thread( struct thread *thread );
|
||||
extern CONTEXT *get_debug_context( struct thread *thread );
|
||||
|
||||
/* mapping functions */
|
||||
|
||||
|
|
|
@ -201,9 +201,9 @@ struct thread *create_process( int fd, struct process *parent,
|
|||
|
||||
/* attach to the debugger if requested */
|
||||
if (process->create_flags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS))
|
||||
debugger_attach( process, current );
|
||||
set_process_debugger( process, current );
|
||||
else if (parent && parent->debugger && !(parent->create_flags & DEBUG_ONLY_THIS_PROCESS))
|
||||
debugger_attach( process, parent->debugger );
|
||||
set_process_debugger( process, parent->debugger );
|
||||
|
||||
release_object( process );
|
||||
return thread;
|
||||
|
|
|
@ -127,16 +127,16 @@ static void fatal_perror( const char *err, ... )
|
|||
}
|
||||
|
||||
/* call a request handler */
|
||||
static void call_req_handler( struct thread *thread, enum request req, int fd )
|
||||
static inline void call_req_handler( struct thread *thread, enum request req )
|
||||
{
|
||||
current = thread;
|
||||
clear_error();
|
||||
|
||||
if (debug_level) trace_request( req, fd );
|
||||
if (debug_level) trace_request( req );
|
||||
|
||||
if (req < REQ_NB_REQUESTS)
|
||||
{
|
||||
req_handlers[req].handler( current->buffer, fd );
|
||||
req_handlers[req]( current->buffer );
|
||||
if (current && !current->wait) send_reply( current );
|
||||
current = NULL;
|
||||
return;
|
||||
|
@ -186,10 +186,8 @@ void read_request( struct thread *thread )
|
|||
|
||||
if (ret == sizeof(req))
|
||||
{
|
||||
int pass_fd = thread->pass_fd;
|
||||
call_req_handler( thread, req );
|
||||
thread->pass_fd = -1;
|
||||
call_req_handler( thread, req, pass_fd );
|
||||
if (pass_fd != -1) close( pass_fd );
|
||||
return;
|
||||
}
|
||||
if (ret == -1)
|
||||
|
|
219
server/request.h
219
server/request.h
|
@ -22,20 +22,26 @@
|
|||
#define PROTOCOL_ERROR -3
|
||||
|
||||
/* request handler definition */
|
||||
#define DECL_HANDLER(name) void req_##name( struct name##_request *req, int fd )
|
||||
#define DECL_HANDLER(name) void req_##name( struct name##_request *req )
|
||||
|
||||
/* request functions */
|
||||
|
||||
#ifdef __GNUC__
|
||||
extern void fatal_protocol_error( struct thread *thread,
|
||||
const char *err, ... ) __attribute__((format (printf,2,3)));
|
||||
#else
|
||||
extern void fatal_protocol_error( struct thread *thread, const char *err, ... );
|
||||
#endif
|
||||
|
||||
extern void read_request( struct thread *thread );
|
||||
extern int write_request( struct thread *thread );
|
||||
extern void fatal_protocol_error( struct thread *thread, const char *err, ... );
|
||||
extern void set_reply_fd( struct thread *thread, int pass_fd );
|
||||
extern void send_reply( struct thread *thread );
|
||||
extern void open_master_socket(void);
|
||||
extern void close_master_socket(void);
|
||||
extern void lock_master_socket( int locked );
|
||||
|
||||
extern void trace_request( enum request req, int fd );
|
||||
extern void trace_request( enum request req );
|
||||
extern void trace_reply( struct thread *thread );
|
||||
|
||||
/* get the request buffer */
|
||||
|
@ -138,7 +144,8 @@ DECL_HANDLER(create_device);
|
|||
DECL_HANDLER(create_snapshot);
|
||||
DECL_HANDLER(next_process);
|
||||
DECL_HANDLER(wait_debug_event);
|
||||
DECL_HANDLER(send_debug_event);
|
||||
DECL_HANDLER(exception_event);
|
||||
DECL_HANDLER(output_debug_string);
|
||||
DECL_HANDLER(continue_debug_event);
|
||||
DECL_HANDLER(debug_process);
|
||||
DECL_HANDLER(read_process_memory);
|
||||
|
@ -170,108 +177,108 @@ DECL_HANDLER(get_atom_name);
|
|||
|
||||
#ifdef WANT_REQUEST_HANDLERS
|
||||
|
||||
static const struct handler {
|
||||
void (*handler)( void *req, int fd );
|
||||
unsigned int min_size;
|
||||
} req_handlers[REQ_NB_REQUESTS] = {
|
||||
{ (void(*)())req_new_process, sizeof(struct new_process_request) },
|
||||
{ (void(*)())req_new_thread, sizeof(struct new_thread_request) },
|
||||
{ (void(*)())req_boot_done, sizeof(struct boot_done_request) },
|
||||
{ (void(*)())req_init_process, sizeof(struct init_process_request) },
|
||||
{ (void(*)())req_init_process_done, sizeof(struct init_process_done_request) },
|
||||
{ (void(*)())req_init_thread, sizeof(struct init_thread_request) },
|
||||
{ (void(*)())req_get_thread_buffer, sizeof(struct get_thread_buffer_request) },
|
||||
{ (void(*)())req_terminate_process, sizeof(struct terminate_process_request) },
|
||||
{ (void(*)())req_terminate_thread, sizeof(struct terminate_thread_request) },
|
||||
{ (void(*)())req_get_process_info, sizeof(struct get_process_info_request) },
|
||||
{ (void(*)())req_set_process_info, sizeof(struct set_process_info_request) },
|
||||
{ (void(*)())req_get_thread_info, sizeof(struct get_thread_info_request) },
|
||||
{ (void(*)())req_set_thread_info, sizeof(struct set_thread_info_request) },
|
||||
{ (void(*)())req_suspend_thread, sizeof(struct suspend_thread_request) },
|
||||
{ (void(*)())req_resume_thread, sizeof(struct resume_thread_request) },
|
||||
{ (void(*)())req_load_dll, sizeof(struct load_dll_request) },
|
||||
{ (void(*)())req_unload_dll, sizeof(struct unload_dll_request) },
|
||||
{ (void(*)())req_queue_apc, sizeof(struct queue_apc_request) },
|
||||
{ (void(*)())req_get_apcs, sizeof(struct get_apcs_request) },
|
||||
{ (void(*)())req_close_handle, sizeof(struct close_handle_request) },
|
||||
{ (void(*)())req_get_handle_info, sizeof(struct get_handle_info_request) },
|
||||
{ (void(*)())req_set_handle_info, sizeof(struct set_handle_info_request) },
|
||||
{ (void(*)())req_dup_handle, sizeof(struct dup_handle_request) },
|
||||
{ (void(*)())req_open_process, sizeof(struct open_process_request) },
|
||||
{ (void(*)())req_select, sizeof(struct select_request) },
|
||||
{ (void(*)())req_create_event, sizeof(struct create_event_request) },
|
||||
{ (void(*)())req_event_op, sizeof(struct event_op_request) },
|
||||
{ (void(*)())req_open_event, sizeof(struct open_event_request) },
|
||||
{ (void(*)())req_create_mutex, sizeof(struct create_mutex_request) },
|
||||
{ (void(*)())req_release_mutex, sizeof(struct release_mutex_request) },
|
||||
{ (void(*)())req_open_mutex, sizeof(struct open_mutex_request) },
|
||||
{ (void(*)())req_create_semaphore, sizeof(struct create_semaphore_request) },
|
||||
{ (void(*)())req_release_semaphore, sizeof(struct release_semaphore_request) },
|
||||
{ (void(*)())req_open_semaphore, sizeof(struct open_semaphore_request) },
|
||||
{ (void(*)())req_create_file, sizeof(struct create_file_request) },
|
||||
{ (void(*)())req_alloc_file_handle, sizeof(struct alloc_file_handle_request) },
|
||||
{ (void(*)())req_get_read_fd, sizeof(struct get_read_fd_request) },
|
||||
{ (void(*)())req_get_write_fd, sizeof(struct get_write_fd_request) },
|
||||
{ (void(*)())req_set_file_pointer, sizeof(struct set_file_pointer_request) },
|
||||
{ (void(*)())req_truncate_file, sizeof(struct truncate_file_request) },
|
||||
{ (void(*)())req_set_file_time, sizeof(struct set_file_time_request) },
|
||||
{ (void(*)())req_flush_file, sizeof(struct flush_file_request) },
|
||||
{ (void(*)())req_get_file_info, sizeof(struct get_file_info_request) },
|
||||
{ (void(*)())req_lock_file, sizeof(struct lock_file_request) },
|
||||
{ (void(*)())req_unlock_file, sizeof(struct unlock_file_request) },
|
||||
{ (void(*)())req_create_pipe, sizeof(struct create_pipe_request) },
|
||||
{ (void(*)())req_create_socket, sizeof(struct create_socket_request) },
|
||||
{ (void(*)())req_accept_socket, sizeof(struct accept_socket_request) },
|
||||
{ (void(*)())req_set_socket_event, sizeof(struct set_socket_event_request) },
|
||||
{ (void(*)())req_get_socket_event, sizeof(struct get_socket_event_request) },
|
||||
{ (void(*)())req_enable_socket_event, sizeof(struct enable_socket_event_request) },
|
||||
{ (void(*)())req_alloc_console, sizeof(struct alloc_console_request) },
|
||||
{ (void(*)())req_free_console, sizeof(struct free_console_request) },
|
||||
{ (void(*)())req_open_console, sizeof(struct open_console_request) },
|
||||
{ (void(*)())req_set_console_fd, sizeof(struct set_console_fd_request) },
|
||||
{ (void(*)())req_get_console_mode, sizeof(struct get_console_mode_request) },
|
||||
{ (void(*)())req_set_console_mode, sizeof(struct set_console_mode_request) },
|
||||
{ (void(*)())req_set_console_info, sizeof(struct set_console_info_request) },
|
||||
{ (void(*)())req_get_console_info, sizeof(struct get_console_info_request) },
|
||||
{ (void(*)())req_write_console_input, sizeof(struct write_console_input_request) },
|
||||
{ (void(*)())req_read_console_input, sizeof(struct read_console_input_request) },
|
||||
{ (void(*)())req_create_change_notification, sizeof(struct create_change_notification_request) },
|
||||
{ (void(*)())req_create_mapping, sizeof(struct create_mapping_request) },
|
||||
{ (void(*)())req_open_mapping, sizeof(struct open_mapping_request) },
|
||||
{ (void(*)())req_get_mapping_info, sizeof(struct get_mapping_info_request) },
|
||||
{ (void(*)())req_create_device, sizeof(struct create_device_request) },
|
||||
{ (void(*)())req_create_snapshot, sizeof(struct create_snapshot_request) },
|
||||
{ (void(*)())req_next_process, sizeof(struct next_process_request) },
|
||||
{ (void(*)())req_wait_debug_event, sizeof(struct wait_debug_event_request) },
|
||||
{ (void(*)())req_send_debug_event, sizeof(struct send_debug_event_request) },
|
||||
{ (void(*)())req_continue_debug_event, sizeof(struct continue_debug_event_request) },
|
||||
{ (void(*)())req_debug_process, sizeof(struct debug_process_request) },
|
||||
{ (void(*)())req_read_process_memory, sizeof(struct read_process_memory_request) },
|
||||
{ (void(*)())req_write_process_memory, sizeof(struct write_process_memory_request) },
|
||||
{ (void(*)())req_create_key, sizeof(struct create_key_request) },
|
||||
{ (void(*)())req_open_key, sizeof(struct open_key_request) },
|
||||
{ (void(*)())req_delete_key, sizeof(struct delete_key_request) },
|
||||
{ (void(*)())req_close_key, sizeof(struct close_key_request) },
|
||||
{ (void(*)())req_enum_key, sizeof(struct enum_key_request) },
|
||||
{ (void(*)())req_query_key_info, sizeof(struct query_key_info_request) },
|
||||
{ (void(*)())req_set_key_value, sizeof(struct set_key_value_request) },
|
||||
{ (void(*)())req_get_key_value, sizeof(struct get_key_value_request) },
|
||||
{ (void(*)())req_enum_key_value, sizeof(struct enum_key_value_request) },
|
||||
{ (void(*)())req_delete_key_value, sizeof(struct delete_key_value_request) },
|
||||
{ (void(*)())req_load_registry, sizeof(struct load_registry_request) },
|
||||
{ (void(*)())req_save_registry, sizeof(struct save_registry_request) },
|
||||
{ (void(*)())req_set_registry_levels, sizeof(struct set_registry_levels_request) },
|
||||
{ (void(*)())req_create_timer, sizeof(struct create_timer_request) },
|
||||
{ (void(*)())req_open_timer, sizeof(struct open_timer_request) },
|
||||
{ (void(*)())req_set_timer, sizeof(struct set_timer_request) },
|
||||
{ (void(*)())req_cancel_timer, sizeof(struct cancel_timer_request) },
|
||||
{ (void(*)())req_get_thread_context, sizeof(struct get_thread_context_request) },
|
||||
{ (void(*)())req_set_thread_context, sizeof(struct set_thread_context_request) },
|
||||
{ (void(*)())req_get_selector_entry, sizeof(struct get_selector_entry_request) },
|
||||
{ (void(*)())req_add_atom, sizeof(struct add_atom_request) },
|
||||
{ (void(*)())req_delete_atom, sizeof(struct delete_atom_request) },
|
||||
{ (void(*)())req_find_atom, sizeof(struct find_atom_request) },
|
||||
{ (void(*)())req_get_atom_name, sizeof(struct get_atom_name_request) },
|
||||
typedef void (*req_handler)( void *req );
|
||||
static const req_handler req_handlers[REQ_NB_REQUESTS] =
|
||||
{
|
||||
(req_handler)req_new_process,
|
||||
(req_handler)req_new_thread,
|
||||
(req_handler)req_boot_done,
|
||||
(req_handler)req_init_process,
|
||||
(req_handler)req_init_process_done,
|
||||
(req_handler)req_init_thread,
|
||||
(req_handler)req_get_thread_buffer,
|
||||
(req_handler)req_terminate_process,
|
||||
(req_handler)req_terminate_thread,
|
||||
(req_handler)req_get_process_info,
|
||||
(req_handler)req_set_process_info,
|
||||
(req_handler)req_get_thread_info,
|
||||
(req_handler)req_set_thread_info,
|
||||
(req_handler)req_suspend_thread,
|
||||
(req_handler)req_resume_thread,
|
||||
(req_handler)req_load_dll,
|
||||
(req_handler)req_unload_dll,
|
||||
(req_handler)req_queue_apc,
|
||||
(req_handler)req_get_apcs,
|
||||
(req_handler)req_close_handle,
|
||||
(req_handler)req_get_handle_info,
|
||||
(req_handler)req_set_handle_info,
|
||||
(req_handler)req_dup_handle,
|
||||
(req_handler)req_open_process,
|
||||
(req_handler)req_select,
|
||||
(req_handler)req_create_event,
|
||||
(req_handler)req_event_op,
|
||||
(req_handler)req_open_event,
|
||||
(req_handler)req_create_mutex,
|
||||
(req_handler)req_release_mutex,
|
||||
(req_handler)req_open_mutex,
|
||||
(req_handler)req_create_semaphore,
|
||||
(req_handler)req_release_semaphore,
|
||||
(req_handler)req_open_semaphore,
|
||||
(req_handler)req_create_file,
|
||||
(req_handler)req_alloc_file_handle,
|
||||
(req_handler)req_get_read_fd,
|
||||
(req_handler)req_get_write_fd,
|
||||
(req_handler)req_set_file_pointer,
|
||||
(req_handler)req_truncate_file,
|
||||
(req_handler)req_set_file_time,
|
||||
(req_handler)req_flush_file,
|
||||
(req_handler)req_get_file_info,
|
||||
(req_handler)req_lock_file,
|
||||
(req_handler)req_unlock_file,
|
||||
(req_handler)req_create_pipe,
|
||||
(req_handler)req_create_socket,
|
||||
(req_handler)req_accept_socket,
|
||||
(req_handler)req_set_socket_event,
|
||||
(req_handler)req_get_socket_event,
|
||||
(req_handler)req_enable_socket_event,
|
||||
(req_handler)req_alloc_console,
|
||||
(req_handler)req_free_console,
|
||||
(req_handler)req_open_console,
|
||||
(req_handler)req_set_console_fd,
|
||||
(req_handler)req_get_console_mode,
|
||||
(req_handler)req_set_console_mode,
|
||||
(req_handler)req_set_console_info,
|
||||
(req_handler)req_get_console_info,
|
||||
(req_handler)req_write_console_input,
|
||||
(req_handler)req_read_console_input,
|
||||
(req_handler)req_create_change_notification,
|
||||
(req_handler)req_create_mapping,
|
||||
(req_handler)req_open_mapping,
|
||||
(req_handler)req_get_mapping_info,
|
||||
(req_handler)req_create_device,
|
||||
(req_handler)req_create_snapshot,
|
||||
(req_handler)req_next_process,
|
||||
(req_handler)req_wait_debug_event,
|
||||
(req_handler)req_exception_event,
|
||||
(req_handler)req_output_debug_string,
|
||||
(req_handler)req_continue_debug_event,
|
||||
(req_handler)req_debug_process,
|
||||
(req_handler)req_read_process_memory,
|
||||
(req_handler)req_write_process_memory,
|
||||
(req_handler)req_create_key,
|
||||
(req_handler)req_open_key,
|
||||
(req_handler)req_delete_key,
|
||||
(req_handler)req_close_key,
|
||||
(req_handler)req_enum_key,
|
||||
(req_handler)req_query_key_info,
|
||||
(req_handler)req_set_key_value,
|
||||
(req_handler)req_get_key_value,
|
||||
(req_handler)req_enum_key_value,
|
||||
(req_handler)req_delete_key_value,
|
||||
(req_handler)req_load_registry,
|
||||
(req_handler)req_save_registry,
|
||||
(req_handler)req_set_registry_levels,
|
||||
(req_handler)req_create_timer,
|
||||
(req_handler)req_open_timer,
|
||||
(req_handler)req_set_timer,
|
||||
(req_handler)req_cancel_timer,
|
||||
(req_handler)req_get_thread_context,
|
||||
(req_handler)req_set_thread_context,
|
||||
(req_handler)req_get_selector_entry,
|
||||
(req_handler)req_add_atom,
|
||||
(req_handler)req_delete_atom,
|
||||
(req_handler)req_find_atom,
|
||||
(req_handler)req_get_atom_name,
|
||||
};
|
||||
#endif /* WANT_REQUEST_HANDLERS */
|
||||
|
||||
|
|
|
@ -126,6 +126,7 @@ struct thread *create_thread( int fd, struct process *process, int suspend )
|
|||
if (!(thread = alloc_object( &thread_ops, fd ))) return NULL;
|
||||
|
||||
thread->unix_pid = 0; /* not known yet */
|
||||
thread->context = NULL;
|
||||
thread->teb = NULL;
|
||||
thread->mutex = NULL;
|
||||
thread->debug_ctx = NULL;
|
||||
|
|
|
@ -47,6 +47,7 @@ struct thread
|
|||
int attached; /* is thread attached with ptrace? */
|
||||
int exit_code; /* thread exit code */
|
||||
int unix_pid; /* Unix pid of client */
|
||||
CONTEXT *context; /* current context if in an exception handler */
|
||||
void *teb; /* TEB address (in client address space) */
|
||||
void *entry; /* thread entry point (in client address space) */
|
||||
int priority; /* priority level */
|
||||
|
|
|
@ -79,23 +79,28 @@ static void dump_context( const CONTEXT *context )
|
|||
#endif
|
||||
}
|
||||
|
||||
static void dump_debug_event_t( const debug_event_t *event )
|
||||
static void dump_exc_record( const EXCEPTION_RECORD *rec )
|
||||
{
|
||||
int i;
|
||||
fprintf( stderr, "{code=%lx,flags=%lx,rec=%p,addr=%p,params={",
|
||||
rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionRecord,
|
||||
rec->ExceptionAddress );
|
||||
for (i = 0; i < rec->NumberParameters; i++)
|
||||
{
|
||||
if (i) fputc( ',', stderr );
|
||||
fprintf( stderr, "%lx", rec->ExceptionInformation[i] );
|
||||
}
|
||||
fputc( '}', stderr );
|
||||
}
|
||||
|
||||
static void dump_debug_event_t( const debug_event_t *event )
|
||||
{
|
||||
switch(event->code)
|
||||
{
|
||||
case EXCEPTION_DEBUG_EVENT:
|
||||
fprintf( stderr, "{exception,code=%x,flags=%x,rec=%p,addr=%p,params={",
|
||||
event->info.exception.code, event->info.exception.flags,
|
||||
event->info.exception.record, event->info.exception.addr );
|
||||
for (i = 0; i < event->info.exception.nb_params; i++)
|
||||
{
|
||||
if (i) fputc( ',', stderr );
|
||||
fprintf( stderr, "%x", event->info.exception.params[i] );
|
||||
}
|
||||
fprintf( stderr, "},first_chance=%d,context=", event->info.exception.first_chance );
|
||||
dump_context( &event->info.exception.context );
|
||||
fputc( '}', stderr );
|
||||
fprintf( stderr, "{exception," );
|
||||
dump_exc_record( &event->info.exception.record );
|
||||
fprintf( stderr, ",first=%d}", event->info.exception.first );
|
||||
break;
|
||||
case CREATE_THREAD_DEBUG_EVENT:
|
||||
fprintf( stderr, "{create_thread,thread=%d,teb=%p,start=%p}",
|
||||
|
@ -927,17 +932,28 @@ static void dump_wait_debug_event_reply( const struct wait_debug_event_request *
|
|||
dump_debug_event_t( &req->event );
|
||||
}
|
||||
|
||||
static void dump_send_debug_event_request( const struct send_debug_event_request *req )
|
||||
static void dump_exception_event_request( const struct exception_event_request *req )
|
||||
{
|
||||
fprintf( stderr, " event=" );
|
||||
dump_debug_event_t( &req->event );
|
||||
fprintf( stderr, " record=" );
|
||||
dump_exc_record( &req->record );
|
||||
fprintf( stderr, "," );
|
||||
fprintf( stderr, " first=%d,", req->first );
|
||||
fprintf( stderr, " context=" );
|
||||
dump_context( &req->context );
|
||||
}
|
||||
|
||||
static void dump_send_debug_event_reply( const struct send_debug_event_request *req )
|
||||
static void dump_exception_event_reply( const struct exception_event_request *req )
|
||||
{
|
||||
fprintf( stderr, " status=%d", req->status );
|
||||
}
|
||||
|
||||
static void dump_output_debug_string_request( const struct output_debug_string_request *req )
|
||||
{
|
||||
fprintf( stderr, " string=%p,", req->string );
|
||||
fprintf( stderr, " unicode=%d,", req->unicode );
|
||||
fprintf( stderr, " length=%d", req->length );
|
||||
}
|
||||
|
||||
static void dump_continue_debug_event_request( const struct continue_debug_event_request *req )
|
||||
{
|
||||
fprintf( stderr, " pid=%p,", req->pid );
|
||||
|
@ -1310,7 +1326,8 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
|
|||
(dump_func)dump_create_snapshot_request,
|
||||
(dump_func)dump_next_process_request,
|
||||
(dump_func)dump_wait_debug_event_request,
|
||||
(dump_func)dump_send_debug_event_request,
|
||||
(dump_func)dump_exception_event_request,
|
||||
(dump_func)dump_output_debug_string_request,
|
||||
(dump_func)dump_continue_debug_event_request,
|
||||
(dump_func)dump_debug_process_request,
|
||||
(dump_func)dump_read_process_memory_request,
|
||||
|
@ -1411,7 +1428,8 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
|
|||
(dump_func)dump_create_snapshot_reply,
|
||||
(dump_func)dump_next_process_reply,
|
||||
(dump_func)dump_wait_debug_event_reply,
|
||||
(dump_func)dump_send_debug_event_reply,
|
||||
(dump_func)dump_exception_event_reply,
|
||||
(dump_func)0,
|
||||
(dump_func)0,
|
||||
(dump_func)0,
|
||||
(dump_func)dump_read_process_memory_reply,
|
||||
|
@ -1512,7 +1530,8 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
|
|||
"create_snapshot",
|
||||
"next_process",
|
||||
"wait_debug_event",
|
||||
"send_debug_event",
|
||||
"exception_event",
|
||||
"output_debug_string",
|
||||
"continue_debug_event",
|
||||
"debug_process",
|
||||
"read_process_memory",
|
||||
|
@ -1546,7 +1565,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
|
|||
/* ### make_requests end ### */
|
||||
/* Everything above this line is generated automatically by tools/make_requests */
|
||||
|
||||
void trace_request( enum request req, int fd )
|
||||
void trace_request( enum request req )
|
||||
{
|
||||
current->last_req = req;
|
||||
if (req < REQ_NB_REQUESTS)
|
||||
|
@ -1556,7 +1575,7 @@ void trace_request( enum request req, int fd )
|
|||
}
|
||||
else
|
||||
fprintf( stderr, "%08x: %d(", (unsigned int)current, req );
|
||||
if (fd != -1) fprintf( stderr, " ) fd=%d\n", fd );
|
||||
if (current->pass_fd != -1) fprintf( stderr, " ) fd=%d\n", current->pass_fd );
|
||||
else fprintf( stderr, " )\n" );
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
"path_t" => "&dump_path_t",
|
||||
"debug_event_t" => "&dump_debug_event_t",
|
||||
"CONTEXT" => "&dump_context",
|
||||
"EXCEPTION_RECORD" => "&dump_exc_record",
|
||||
"char[1]" => "\\\"%s\\\"",
|
||||
"WCHAR[1]" => "&dump_unicode_string"
|
||||
);
|
||||
|
@ -80,13 +81,11 @@ my @request_lines = ();
|
|||
|
||||
foreach $req (@requests) { push @request_lines, "DECL_HANDLER($req);\n"; }
|
||||
push @request_lines, "\n#ifdef WANT_REQUEST_HANDLERS\n\n";
|
||||
push @request_lines, "static const struct handler {\n";
|
||||
push @request_lines, " void (*handler)( void *req, int fd );\n";
|
||||
push @request_lines, " unsigned int min_size;\n";
|
||||
push @request_lines, "} req_handlers[REQ_NB_REQUESTS] = {\n";
|
||||
push @request_lines, "typedef void (*req_handler)( void *req );\n";
|
||||
push @request_lines, "static const req_handler req_handlers[REQ_NB_REQUESTS] =\n{\n";
|
||||
foreach $req (@requests)
|
||||
{
|
||||
push @request_lines, " { (void(*)())req_$req, sizeof(struct ${req}_request) },\n";
|
||||
push @request_lines, " (req_handler)req_$req,\n";
|
||||
}
|
||||
push @request_lines, "};\n#endif /* WANT_REQUEST_HANDLERS */\n";
|
||||
|
||||
|
|
|
@ -34,9 +34,10 @@
|
|||
#include "process.h"
|
||||
#include "thread.h"
|
||||
#include "stackframe.h"
|
||||
#include "server.h"
|
||||
#include "debugtools.h"
|
||||
|
||||
DEFAULT_DEBUG_CHANNEL(seh)
|
||||
DEFAULT_DEBUG_CHANNEL(seh);
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
|
@ -69,12 +70,16 @@ void WINAPI RaiseException( DWORD code, DWORD flags, DWORD nbargs, const LPDWORD
|
|||
*/
|
||||
DWORD WINAPI UnhandledExceptionFilter(PEXCEPTION_POINTERS epointers)
|
||||
{
|
||||
struct exception_event_request *req = get_req_buffer();
|
||||
char message[80];
|
||||
PDB *pdb = PROCESS_Current();
|
||||
|
||||
if (DEBUG_SendExceptionEvent( epointers->ExceptionRecord, FALSE,
|
||||
epointers->ContextRecord ) == DBG_CONTINUE)
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
/* send a last chance event to the debugger */
|
||||
req->record = *epointers->ExceptionRecord;
|
||||
req->first = 0;
|
||||
req->context = *epointers->ContextRecord;
|
||||
if (!server_call_noerr( REQ_EXCEPTION_EVENT )) *epointers->ContextRecord = req->context;
|
||||
if (req->status == DBG_CONTINUE) return EXCEPTION_CONTINUE_EXECUTION;
|
||||
|
||||
if (pdb->top_filter)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue