Added Get/SetThreadContext support through the server.
This commit is contained in:
parent
681c75bf17
commit
3e2517caa7
178
include/server.h
178
include/server.h
|
@ -27,6 +27,86 @@
|
|||
/* a path name for server requests (Unicode) */
|
||||
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 */
|
||||
};
|
||||
struct debug_event_create_thread
|
||||
{
|
||||
int handle; /* handle to the new thread */
|
||||
void *teb; /* thread teb (in debugged process address space) */
|
||||
void *start; /* thread startup routine */
|
||||
};
|
||||
struct debug_event_create_process
|
||||
{
|
||||
int file; /* handle to the process exe file */
|
||||
int process; /* handle to the new process */
|
||||
int thread; /* handle to the new thread */
|
||||
void *base; /* base of executable image */
|
||||
int dbg_offset; /* offset of debug info in file */
|
||||
int dbg_size; /* size of debug info */
|
||||
void *teb; /* thread teb (in debugged process address space) */
|
||||
void *start; /* thread startup routine */
|
||||
void *name; /* image name (optional) */
|
||||
int unicode; /* is it Unicode? */
|
||||
};
|
||||
struct debug_event_exit
|
||||
{
|
||||
int exit_code; /* thread or process exit code */
|
||||
};
|
||||
struct debug_event_load_dll
|
||||
{
|
||||
int handle; /* file handle for the dll */
|
||||
void *base; /* base address of the dll */
|
||||
int dbg_offset; /* offset of debug info in file */
|
||||
int dbg_size; /* size of debug info */
|
||||
void *name; /* image name (optional) */
|
||||
int unicode; /* is it Unicode? */
|
||||
};
|
||||
struct debug_event_unload_dll
|
||||
{
|
||||
void *base; /* base address of the dll */
|
||||
};
|
||||
struct debug_event_output_string
|
||||
{
|
||||
void *string; /* string to display (in debugged process address space) */
|
||||
int unicode; /* is it Unicode? */
|
||||
int length; /* string length */
|
||||
};
|
||||
struct debug_event_rip_info
|
||||
{
|
||||
int error; /* ??? */
|
||||
int type; /* ??? */
|
||||
};
|
||||
union debug_event_data
|
||||
{
|
||||
struct debug_event_exception exception;
|
||||
struct debug_event_create_thread create_thread;
|
||||
struct debug_event_create_process create_process;
|
||||
struct debug_event_exit exit;
|
||||
struct debug_event_load_dll load_dll;
|
||||
struct debug_event_unload_dll unload_dll;
|
||||
struct debug_event_output_string output_string;
|
||||
struct debug_event_rip_info rip_info;
|
||||
};
|
||||
|
||||
/* debug event data */
|
||||
typedef struct
|
||||
{
|
||||
int code; /* event code */
|
||||
union debug_event_data info; /* event information */
|
||||
} debug_event_t;
|
||||
|
||||
|
||||
/* Create a new process from the context of the parent */
|
||||
struct new_process_request
|
||||
{
|
||||
|
@ -708,91 +788,17 @@ struct next_process_request
|
|||
struct wait_debug_event_request
|
||||
{
|
||||
IN int timeout; /* timeout in ms */
|
||||
OUT int code; /* event code */
|
||||
OUT void* pid; /* process id */
|
||||
OUT void* tid; /* thread id */
|
||||
/* OUT union debug_event_data data; */
|
||||
OUT debug_event_t event; /* debug event data */
|
||||
};
|
||||
|
||||
|
||||
/* Send a debug event */
|
||||
struct send_debug_event_request
|
||||
{
|
||||
IN int code; /* event code */
|
||||
OUT int status; /* event continuation status */
|
||||
/* IN union debug_event_data data; */
|
||||
};
|
||||
|
||||
|
||||
/* 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 */
|
||||
};
|
||||
struct debug_event_create_thread
|
||||
{
|
||||
int handle; /* handle to the new thread */
|
||||
void *teb; /* thread teb (in debugged process address space) */
|
||||
void *start; /* thread startup routine */
|
||||
};
|
||||
struct debug_event_create_process
|
||||
{
|
||||
int file; /* handle to the process exe file */
|
||||
int process; /* handle to the new process */
|
||||
int thread; /* handle to the new thread */
|
||||
void *base; /* base of executable image */
|
||||
int dbg_offset; /* offset of debug info in file */
|
||||
int dbg_size; /* size of debug info */
|
||||
void *teb; /* thread teb (in debugged process address space) */
|
||||
void *start; /* thread startup routine */
|
||||
void *name; /* image name (optional) */
|
||||
int unicode; /* is it Unicode? */
|
||||
};
|
||||
struct debug_event_exit
|
||||
{
|
||||
int exit_code; /* thread or process exit code */
|
||||
};
|
||||
struct debug_event_load_dll
|
||||
{
|
||||
int handle; /* file handle for the dll */
|
||||
void *base; /* base address of the dll */
|
||||
int dbg_offset; /* offset of debug info in file */
|
||||
int dbg_size; /* size of debug info */
|
||||
void *name; /* image name (optional) */
|
||||
int unicode; /* is it Unicode? */
|
||||
};
|
||||
struct debug_event_unload_dll
|
||||
{
|
||||
void *base; /* base address of the dll */
|
||||
};
|
||||
struct debug_event_output_string
|
||||
{
|
||||
void *string; /* string to display (in debugged process address space) */
|
||||
int unicode; /* is it Unicode? */
|
||||
int length; /* string length */
|
||||
};
|
||||
struct debug_event_rip_info
|
||||
{
|
||||
int error; /* ??? */
|
||||
int type; /* ??? */
|
||||
};
|
||||
union debug_event_data
|
||||
{
|
||||
struct debug_event_exception exception;
|
||||
struct debug_event_create_thread create_thread;
|
||||
struct debug_event_create_process create_process;
|
||||
struct debug_event_exit exit;
|
||||
struct debug_event_load_dll load_dll;
|
||||
struct debug_event_unload_dll unload_dll;
|
||||
struct debug_event_output_string output_string;
|
||||
struct debug_event_rip_info rip_info;
|
||||
IN debug_event_t event; /* debug event data */
|
||||
};
|
||||
|
||||
|
||||
|
@ -1005,6 +1011,24 @@ struct cancel_timer_request
|
|||
};
|
||||
|
||||
|
||||
/* Retrieve the current context of a thread */
|
||||
struct get_thread_context_request
|
||||
{
|
||||
IN int handle; /* thread handle */
|
||||
IN unsigned int flags; /* context flags */
|
||||
OUT CONTEXT context; /* thread context */
|
||||
};
|
||||
|
||||
|
||||
/* Set the current context of a thread */
|
||||
struct set_thread_context_request
|
||||
{
|
||||
IN int handle; /* thread handle */
|
||||
IN unsigned int flags; /* context flags */
|
||||
IN CONTEXT context; /* thread context */
|
||||
};
|
||||
|
||||
|
||||
/* Everything below this line is generated automatically by tools/make_requests */
|
||||
/* ### make_requests begin ### */
|
||||
|
||||
|
@ -1100,6 +1124,8 @@ enum request
|
|||
REQ_OPEN_TIMER,
|
||||
REQ_SET_TIMER,
|
||||
REQ_CANCEL_TIMER,
|
||||
REQ_GET_THREAD_CONTEXT,
|
||||
REQ_SET_THREAD_CONTEXT,
|
||||
REQ_NB_REQUESTS
|
||||
};
|
||||
|
||||
|
|
|
@ -11,22 +11,7 @@
|
|||
#include "server.h"
|
||||
#include "debugtools.h"
|
||||
|
||||
DEFAULT_DEBUG_CHANNEL(debugstr)
|
||||
|
||||
/**********************************************************************
|
||||
* DEBUG_SendEvent
|
||||
*
|
||||
* Internal helper to send a debug event request to the server.
|
||||
*/
|
||||
static DWORD DEBUG_SendEvent( int code, void *data, int size )
|
||||
{
|
||||
DWORD ret = 0;
|
||||
struct send_debug_event_request *req = get_req_buffer();
|
||||
req->code = code;
|
||||
memcpy( req + 1, data, size );
|
||||
if (!server_call( REQ_SEND_DEBUG_EVENT )) ret = req->status;
|
||||
return ret;
|
||||
}
|
||||
DEFAULT_DEBUG_CHANNEL(debugstr);
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
|
@ -39,21 +24,21 @@ DWORD DEBUG_SendExceptionEvent( EXCEPTION_RECORD *rec, BOOL first_chance, CONTEX
|
|||
int i;
|
||||
DWORD ret = 0;
|
||||
struct send_debug_event_request *req = get_req_buffer();
|
||||
struct debug_event_exception *event = (struct debug_event_exception *)(req + 1);
|
||||
|
||||
req->code = EXCEPTION_DEBUG_EVENT;
|
||||
event->code = rec->ExceptionCode;
|
||||
event->flags = rec->ExceptionFlags;
|
||||
event->record = rec->ExceptionRecord;
|
||||
event->addr = rec->ExceptionAddress;
|
||||
event->nb_params = rec->NumberParameters;
|
||||
for (i = 0; i < event->nb_params; i++) event->params[i] = rec->ExceptionInformation[i];
|
||||
event->first_chance = first_chance;
|
||||
event->context = *context;
|
||||
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( REQ_SEND_DEBUG_EVENT ))
|
||||
{
|
||||
ret = req->status;
|
||||
*context = event->context;
|
||||
*context = req->event.info.exception.context;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -67,22 +52,24 @@ DWORD DEBUG_SendExceptionEvent( EXCEPTION_RECORD *rec, BOOL first_chance, CONTEX
|
|||
*/
|
||||
DWORD DEBUG_SendCreateProcessEvent( HFILE file, HMODULE module, void *entry )
|
||||
{
|
||||
struct debug_event_create_process event;
|
||||
DWORD ret = 0;
|
||||
struct send_debug_event_request *req = get_req_buffer();
|
||||
|
||||
event.file = file;
|
||||
event.process = 0; /* will be filled by server */
|
||||
event.thread = 0; /* will be filled by server */
|
||||
event.base = (void *)module;
|
||||
event.dbg_offset = 0; /* FIXME */
|
||||
event.dbg_size = 0; /* FIXME */
|
||||
event.teb = NtCurrentTeb();
|
||||
event.start = entry;
|
||||
event.name = 0; /* FIXME */
|
||||
event.unicode = 0; /* FIXME */
|
||||
return DEBUG_SendEvent( CREATE_PROCESS_DEBUG_EVENT, &event, sizeof(event) );
|
||||
req->event.code = CREATE_PROCESS_DEBUG_EVENT;
|
||||
req->event.info.create_process.file = file;
|
||||
req->event.info.create_process.process = 0; /* will be filled by server */
|
||||
req->event.info.create_process.thread = 0; /* will be filled by server */
|
||||
req->event.info.create_process.base = (void *)module;
|
||||
req->event.info.create_process.dbg_offset = 0; /* FIXME */
|
||||
req->event.info.create_process.dbg_size = 0; /* FIXME */
|
||||
req->event.info.create_process.teb = NtCurrentTeb();
|
||||
req->event.info.create_process.start = entry;
|
||||
req->event.info.create_process.name = 0; /* FIXME */
|
||||
req->event.info.create_process.unicode = 0; /* FIXME */
|
||||
if (!server_call( REQ_SEND_DEBUG_EVENT )) ret = req->status;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* DEBUG_SendCreateThreadEvent
|
||||
*
|
||||
|
@ -91,12 +78,15 @@ DWORD DEBUG_SendCreateProcessEvent( HFILE file, HMODULE module, void *entry )
|
|||
*/
|
||||
DWORD DEBUG_SendCreateThreadEvent( void *entry )
|
||||
{
|
||||
struct debug_event_create_thread event;
|
||||
DWORD ret = 0;
|
||||
struct send_debug_event_request *req = get_req_buffer();
|
||||
|
||||
event.handle = 0; /* will be filled by server */
|
||||
event.teb = NtCurrentTeb();
|
||||
event.start = entry;
|
||||
return DEBUG_SendEvent( CREATE_THREAD_DEBUG_EVENT, &event, sizeof(event) );
|
||||
req->event.code = CREATE_THREAD_DEBUG_EVENT;
|
||||
req->event.info.create_thread.handle = 0; /* will be filled by server */
|
||||
req->event.info.create_thread.teb = NtCurrentTeb();
|
||||
req->event.info.create_thread.start = entry;
|
||||
if (!server_call( REQ_SEND_DEBUG_EVENT )) ret = req->status;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
@ -107,15 +97,18 @@ DWORD DEBUG_SendCreateThreadEvent( void *entry )
|
|||
*/
|
||||
DWORD DEBUG_SendLoadDLLEvent( HFILE file, HMODULE module, LPSTR *name )
|
||||
{
|
||||
struct debug_event_load_dll event;
|
||||
DWORD ret = 0;
|
||||
struct send_debug_event_request *req = get_req_buffer();
|
||||
|
||||
event.handle = file;
|
||||
event.base = (void *)module;
|
||||
event.dbg_offset = 0; /* FIXME */
|
||||
event.dbg_size = 0; /* FIXME */
|
||||
event.name = name;
|
||||
event.unicode = 0;
|
||||
return DEBUG_SendEvent( LOAD_DLL_DEBUG_EVENT, &event, sizeof(event) );
|
||||
req->event.code = LOAD_DLL_DEBUG_EVENT;
|
||||
req->event.info.load_dll.handle = file;
|
||||
req->event.info.load_dll.base = (void *)module;
|
||||
req->event.info.load_dll.dbg_offset = 0; /* FIXME */
|
||||
req->event.info.load_dll.dbg_size = 0; /* FIXME */
|
||||
req->event.info.load_dll.name = name;
|
||||
req->event.info.load_dll.unicode = 0;
|
||||
if (!server_call( REQ_SEND_DEBUG_EVENT )) ret = req->status;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
@ -126,10 +119,13 @@ DWORD DEBUG_SendLoadDLLEvent( HFILE file, HMODULE module, LPSTR *name )
|
|||
*/
|
||||
DWORD DEBUG_SendUnloadDLLEvent( HMODULE module )
|
||||
{
|
||||
struct debug_event_unload_dll event;
|
||||
DWORD ret = 0;
|
||||
struct send_debug_event_request *req = get_req_buffer();
|
||||
|
||||
event.base = (void *)module;
|
||||
return DEBUG_SendEvent( UNLOAD_DLL_DEBUG_EVENT, &event, sizeof(event) );
|
||||
req->event.code = UNLOAD_DLL_DEBUG_EVENT;
|
||||
req->event.info.unload_dll.base = (void *)module;
|
||||
if (!server_call( REQ_SEND_DEBUG_EVENT )) ret = req->status;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
@ -147,73 +143,72 @@ DWORD DEBUG_SendUnloadDLLEvent( HMODULE module )
|
|||
BOOL WINAPI WaitForDebugEvent( LPDEBUG_EVENT event, DWORD timeout )
|
||||
{
|
||||
struct wait_debug_event_request *req = get_req_buffer();
|
||||
union debug_event_data *data = (union debug_event_data *)(req + 1);
|
||||
int i;
|
||||
|
||||
req->timeout = timeout;
|
||||
if (server_call( REQ_WAIT_DEBUG_EVENT )) return FALSE;
|
||||
if ((req->code < 0) || (req->code > RIP_EVENT))
|
||||
server_protocol_error( "WaitForDebugEvent: bad code %d\n", req->code );
|
||||
if ((req->event.code < 0) || (req->event.code > RIP_EVENT))
|
||||
server_protocol_error( "WaitForDebugEvent: bad code %d\n", req->event.code );
|
||||
|
||||
event->dwDebugEventCode = req->code;
|
||||
event->dwDebugEventCode = req->event.code;
|
||||
event->dwProcessId = (DWORD)req->pid;
|
||||
event->dwThreadId = (DWORD)req->tid;
|
||||
switch(req->code)
|
||||
switch(req->event.code)
|
||||
{
|
||||
case EXCEPTION_DEBUG_EVENT:
|
||||
event->u.Exception.ExceptionRecord.ExceptionCode = data->exception.code;
|
||||
event->u.Exception.ExceptionRecord.ExceptionFlags = data->exception.flags;
|
||||
event->u.Exception.ExceptionRecord.ExceptionRecord = data->exception.record;
|
||||
event->u.Exception.ExceptionRecord.ExceptionAddress = data->exception.addr;
|
||||
event->u.Exception.ExceptionRecord.NumberParameters = data->exception.nb_params;
|
||||
for (i = 0; i < data->exception.nb_params; i++)
|
||||
event->u.Exception.ExceptionRecord.ExceptionInformation[i] = data->exception.params[i];
|
||||
event->u.Exception.dwFirstChance = data->exception.first_chance;
|
||||
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;
|
||||
break;
|
||||
case CREATE_THREAD_DEBUG_EVENT:
|
||||
event->u.CreateThread.hThread = data->create_thread.handle;
|
||||
event->u.CreateThread.lpThreadLocalBase = data->create_thread.teb;
|
||||
event->u.CreateThread.lpStartAddress = data->create_thread.start;
|
||||
event->u.CreateThread.hThread = req->event.info.create_thread.handle;
|
||||
event->u.CreateThread.lpThreadLocalBase = req->event.info.create_thread.teb;
|
||||
event->u.CreateThread.lpStartAddress = req->event.info.create_thread.start;
|
||||
break;
|
||||
case CREATE_PROCESS_DEBUG_EVENT:
|
||||
event->u.CreateProcessInfo.hFile = data->create_process.file;
|
||||
event->u.CreateProcessInfo.hProcess = data->create_process.process;
|
||||
event->u.CreateProcessInfo.hThread = data->create_process.thread;
|
||||
event->u.CreateProcessInfo.lpBaseOfImage = data->create_process.base;
|
||||
event->u.CreateProcessInfo.dwDebugInfoFileOffset = data->create_process.dbg_offset;
|
||||
event->u.CreateProcessInfo.nDebugInfoSize = data->create_process.dbg_size;
|
||||
event->u.CreateProcessInfo.lpThreadLocalBase = data->create_process.teb;
|
||||
event->u.CreateProcessInfo.lpStartAddress = data->create_process.start;
|
||||
event->u.CreateProcessInfo.lpImageName = data->create_process.name;
|
||||
event->u.CreateProcessInfo.fUnicode = data->create_process.unicode;
|
||||
if (data->create_process.file == -1) event->u.CreateProcessInfo.hFile = 0;
|
||||
event->u.CreateProcessInfo.hFile = req->event.info.create_process.file;
|
||||
event->u.CreateProcessInfo.hProcess = req->event.info.create_process.process;
|
||||
event->u.CreateProcessInfo.hThread = req->event.info.create_process.thread;
|
||||
event->u.CreateProcessInfo.lpBaseOfImage = req->event.info.create_process.base;
|
||||
event->u.CreateProcessInfo.dwDebugInfoFileOffset = req->event.info.create_process.dbg_offset;
|
||||
event->u.CreateProcessInfo.nDebugInfoSize = req->event.info.create_process.dbg_size;
|
||||
event->u.CreateProcessInfo.lpThreadLocalBase = req->event.info.create_process.teb;
|
||||
event->u.CreateProcessInfo.lpStartAddress = req->event.info.create_process.start;
|
||||
event->u.CreateProcessInfo.lpImageName = req->event.info.create_process.name;
|
||||
event->u.CreateProcessInfo.fUnicode = req->event.info.create_process.unicode;
|
||||
if (req->event.info.create_process.file == -1) event->u.CreateProcessInfo.hFile = 0;
|
||||
break;
|
||||
case EXIT_THREAD_DEBUG_EVENT:
|
||||
event->u.ExitThread.dwExitCode = data->exit.exit_code;
|
||||
event->u.ExitThread.dwExitCode = req->event.info.exit.exit_code;
|
||||
break;
|
||||
case EXIT_PROCESS_DEBUG_EVENT:
|
||||
event->u.ExitProcess.dwExitCode = data->exit.exit_code;
|
||||
event->u.ExitProcess.dwExitCode = req->event.info.exit.exit_code;
|
||||
break;
|
||||
case LOAD_DLL_DEBUG_EVENT:
|
||||
event->u.LoadDll.hFile = data->load_dll.handle;
|
||||
event->u.LoadDll.lpBaseOfDll = data->load_dll.base;
|
||||
event->u.LoadDll.dwDebugInfoFileOffset = data->load_dll.dbg_offset;
|
||||
event->u.LoadDll.nDebugInfoSize = data->load_dll.dbg_size;
|
||||
event->u.LoadDll.lpImageName = data->load_dll.name;
|
||||
event->u.LoadDll.fUnicode = data->load_dll.unicode;
|
||||
if (data->load_dll.handle == -1) event->u.LoadDll.hFile = 0;
|
||||
event->u.LoadDll.hFile = req->event.info.load_dll.handle;
|
||||
event->u.LoadDll.lpBaseOfDll = req->event.info.load_dll.base;
|
||||
event->u.LoadDll.dwDebugInfoFileOffset = req->event.info.load_dll.dbg_offset;
|
||||
event->u.LoadDll.nDebugInfoSize = req->event.info.load_dll.dbg_size;
|
||||
event->u.LoadDll.lpImageName = req->event.info.load_dll.name;
|
||||
event->u.LoadDll.fUnicode = req->event.info.load_dll.unicode;
|
||||
if (req->event.info.load_dll.handle == -1) event->u.LoadDll.hFile = 0;
|
||||
break;
|
||||
case UNLOAD_DLL_DEBUG_EVENT:
|
||||
event->u.UnloadDll.lpBaseOfDll = data->unload_dll.base;
|
||||
event->u.UnloadDll.lpBaseOfDll = req->event.info.unload_dll.base;
|
||||
break;
|
||||
case OUTPUT_DEBUG_STRING_EVENT:
|
||||
event->u.DebugString.lpDebugStringData = data->output_string.string;
|
||||
event->u.DebugString.fUnicode = data->output_string.unicode;
|
||||
event->u.DebugString.nDebugStringLength = data->output_string.length;
|
||||
event->u.DebugString.lpDebugStringData = req->event.info.output_string.string;
|
||||
event->u.DebugString.fUnicode = req->event.info.output_string.unicode;
|
||||
event->u.DebugString.nDebugStringLength = req->event.info.output_string.length;
|
||||
break;
|
||||
case RIP_EVENT:
|
||||
event->u.RipInfo.dwError = data->rip_info.error;
|
||||
event->u.RipInfo.dwType = data->rip_info.type;
|
||||
event->u.RipInfo.dwError = req->event.info.rip_info.error;
|
||||
event->u.RipInfo.dwType = req->event.info.rip_info.type;
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
|
@ -251,11 +246,12 @@ void WINAPI OutputDebugStringA( LPCSTR str )
|
|||
{
|
||||
if (PROCESS_Current()->flags & PDB32_DEBUGGED)
|
||||
{
|
||||
struct debug_event_output_string event;
|
||||
event.string = (void *)str;
|
||||
event.unicode = 0;
|
||||
event.length = strlen(str) + 1;
|
||||
DEBUG_SendEvent( OUTPUT_DEBUG_STRING_EVENT, &event, sizeof(event) );
|
||||
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( REQ_SEND_DEBUG_EVENT );
|
||||
}
|
||||
|
||||
TRACE("%s\n", str);
|
||||
|
@ -269,11 +265,12 @@ void WINAPI OutputDebugStringW( LPCWSTR str )
|
|||
{
|
||||
if (PROCESS_Current()->flags & PDB32_DEBUGGED)
|
||||
{
|
||||
struct debug_event_output_string event;
|
||||
event.string = (void *)str;
|
||||
event.unicode = 1;
|
||||
event.length = (lstrlenW(str) + 1) * sizeof(WCHAR);
|
||||
DEBUG_SendEvent( OUTPUT_DEBUG_STRING_EVENT, &event, sizeof(event) );
|
||||
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( REQ_SEND_DEBUG_EVENT );
|
||||
}
|
||||
|
||||
TRACE("%s\n", debugstr_w(str));
|
||||
|
|
|
@ -516,14 +516,17 @@ BOOL WINAPI TlsSetValue(
|
|||
* Success: TRUE
|
||||
* Failure: FALSE
|
||||
*/
|
||||
BOOL WINAPI SetThreadContext(
|
||||
HANDLE handle, /* [in] Handle to thread with context */
|
||||
const CONTEXT *context) /* [out] Address of context structure */
|
||||
BOOL WINAPI SetThreadContext( HANDLE handle, /* [in] Handle to thread with context */
|
||||
const CONTEXT *context ) /* [in] Address of context structure */
|
||||
{
|
||||
FIXME("not implemented\n" );
|
||||
return TRUE;
|
||||
struct set_thread_context_request *req = get_req_buffer();
|
||||
req->handle = handle;
|
||||
req->flags = context->ContextFlags;
|
||||
memcpy( &req->context, context, sizeof(*context) );
|
||||
return !server_call( REQ_SET_THREAD_CONTEXT );
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* GetThreadContext [KERNEL32.294] Retrieves context of thread.
|
||||
*
|
||||
|
@ -531,25 +534,15 @@ BOOL WINAPI SetThreadContext(
|
|||
* Success: TRUE
|
||||
* Failure: FALSE
|
||||
*/
|
||||
BOOL WINAPI GetThreadContext(
|
||||
HANDLE handle, /* [in] Handle to thread with context */
|
||||
CONTEXT *context) /* [out] Address of context structure */
|
||||
BOOL WINAPI GetThreadContext( HANDLE handle, /* [in] Handle to thread with context */
|
||||
CONTEXT *context ) /* [out] Address of context structure */
|
||||
{
|
||||
#ifdef __i386__
|
||||
WORD cs, ds;
|
||||
|
||||
FIXME("returning dummy info\n" );
|
||||
|
||||
/* make up some plausible values for segment registers */
|
||||
GET_CS(cs);
|
||||
GET_DS(ds);
|
||||
context->SegCs = cs;
|
||||
context->SegDs = ds;
|
||||
context->SegEs = ds;
|
||||
context->SegGs = ds;
|
||||
context->SegSs = ds;
|
||||
context->SegFs = ds;
|
||||
#endif
|
||||
struct get_thread_context_request *req = get_req_buffer();
|
||||
req->handle = handle;
|
||||
req->flags = context->ContextFlags;
|
||||
memcpy( &req->context, context, sizeof(*context) );
|
||||
if (server_call( REQ_GET_THREAD_CONTEXT )) return FALSE;
|
||||
memcpy( context, &req->context, sizeof(*context) );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ MODULE = server
|
|||
C_SRCS = \
|
||||
change.c \
|
||||
console.c \
|
||||
context_i386.c \
|
||||
debugger.c \
|
||||
device.c \
|
||||
event.c \
|
||||
|
|
|
@ -0,0 +1,264 @@
|
|||
/*
|
||||
* i386 register context support
|
||||
*
|
||||
* Copyright (C) 1999 Alexandre Julliard
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef __i386__
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/user.h>
|
||||
|
||||
#include "winbase.h"
|
||||
#include "winerror.h"
|
||||
|
||||
#include "thread.h"
|
||||
#include "request.h"
|
||||
|
||||
|
||||
#ifndef PTRACE_PEEKUSER
|
||||
#define PTRACE_PEEKUSER PT_READ_U
|
||||
#endif
|
||||
#ifndef PTRACE_POKEUSER
|
||||
#define PTRACE_POKEUSER PT_WRITE_U
|
||||
#endif
|
||||
#ifndef PTRACE_GETREGS
|
||||
#define PTRACE_GETREGS PT_GETREGS
|
||||
#endif
|
||||
#ifndef PTRACE_GETFPREGS
|
||||
#define PTRACE_GETFPREGS PT_GETFPREGS
|
||||
#endif
|
||||
|
||||
#ifdef linux
|
||||
|
||||
/* debug register offset in struct user */
|
||||
#define DR_OFFSET(dr) ((int)((((struct user *)0)->u_debugreg) + (dr)))
|
||||
|
||||
/* retrieve a debug register */
|
||||
static inline int get_debug_reg( int pid, int num, DWORD *data )
|
||||
{
|
||||
int res = ptrace( PTRACE_PEEKUSER, pid, DR_OFFSET(num), 0 );
|
||||
if ((res == -1) && errno)
|
||||
{
|
||||
file_set_error();
|
||||
return -1;
|
||||
}
|
||||
*data = res;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* retrieve a thread context */
|
||||
static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
|
||||
{
|
||||
int pid = thread->unix_pid;
|
||||
if (flags & CONTEXT_FULL)
|
||||
{
|
||||
struct user_regs_struct regs;
|
||||
if (ptrace( PTRACE_GETREGS, pid, 0, ®s ) == -1) goto error;
|
||||
if (flags & CONTEXT_INTEGER)
|
||||
{
|
||||
context->Eax = regs.eax;
|
||||
context->Ebx = regs.ebx;
|
||||
context->Ecx = regs.ecx;
|
||||
context->Edx = regs.edx;
|
||||
context->Esi = regs.esi;
|
||||
context->Edi = regs.edi;
|
||||
}
|
||||
if (flags & CONTEXT_CONTROL)
|
||||
{
|
||||
context->Ebp = regs.ebp;
|
||||
context->Esp = regs.esp;
|
||||
context->Eip = regs.eip;
|
||||
context->SegCs = regs.xcs & 0xffff;
|
||||
context->SegSs = regs.xss & 0xffff;
|
||||
context->EFlags = regs.eflags;
|
||||
}
|
||||
if (flags & CONTEXT_SEGMENTS)
|
||||
{
|
||||
context->SegDs = regs.xds & 0xffff;
|
||||
context->SegEs = regs.xes & 0xffff;
|
||||
context->SegFs = regs.xfs & 0xffff;
|
||||
context->SegGs = regs.xgs & 0xffff;
|
||||
}
|
||||
}
|
||||
if (flags & CONTEXT_DEBUG_REGISTERS)
|
||||
{
|
||||
if (get_debug_reg( pid, 0, &context->Dr0 ) == -1) goto error;
|
||||
if (get_debug_reg( pid, 1, &context->Dr1 ) == -1) goto error;
|
||||
if (get_debug_reg( pid, 2, &context->Dr2 ) == -1) goto error;
|
||||
if (get_debug_reg( pid, 3, &context->Dr3 ) == -1) goto error;
|
||||
if (get_debug_reg( pid, 6, &context->Dr6 ) == -1) goto error;
|
||||
if (get_debug_reg( pid, 7, &context->Dr7 ) == -1) goto error;
|
||||
}
|
||||
if (flags & CONTEXT_FLOATING_POINT)
|
||||
{
|
||||
/* we can use context->FloatSave directly as it is using the */
|
||||
/* correct structure (the same as fsave/frstor) */
|
||||
if (ptrace( PTRACE_GETFPREGS, pid, 0, &context->FloatSave ) == -1) goto error;
|
||||
context->FloatSave.Cr0NpxState = 0; /* FIXME */
|
||||
}
|
||||
return;
|
||||
error:
|
||||
file_set_error();
|
||||
}
|
||||
|
||||
|
||||
/* set a thread context */
|
||||
static void set_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
|
||||
{
|
||||
int pid = thread->unix_pid;
|
||||
if (flags & CONTEXT_FULL)
|
||||
{
|
||||
struct user_regs_struct regs;
|
||||
if ((flags & CONTEXT_FULL) != CONTEXT_FULL) /* need to preserve some registers */
|
||||
{
|
||||
if (ptrace( PTRACE_GETREGS, pid, 0, ®s ) == -1) goto error;
|
||||
}
|
||||
if (flags & CONTEXT_INTEGER)
|
||||
{
|
||||
regs.eax = context->Eax;
|
||||
regs.ebx = context->Ebx;
|
||||
regs.ecx = context->Ecx;
|
||||
regs.edx = context->Edx;
|
||||
regs.esi = context->Esi;
|
||||
regs.edi = context->Edi;
|
||||
}
|
||||
if (flags & CONTEXT_CONTROL)
|
||||
{
|
||||
regs.ebp = context->Ebp;
|
||||
regs.esp = context->Esp;
|
||||
regs.eip = context->Eip;
|
||||
regs.xcs = context->SegCs;
|
||||
regs.xss = context->SegSs;
|
||||
regs.eflags = context->EFlags;
|
||||
}
|
||||
if (flags & CONTEXT_SEGMENTS)
|
||||
{
|
||||
regs.xds = context->SegDs;
|
||||
regs.xes = context->SegEs;
|
||||
regs.xfs = context->SegFs;
|
||||
regs.xgs = context->SegGs;
|
||||
}
|
||||
if (ptrace( PTRACE_SETREGS, pid, 0, ®s ) == -1) goto error;
|
||||
}
|
||||
if (flags & CONTEXT_DEBUG_REGISTERS)
|
||||
{
|
||||
if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(0), context->Dr0 ) == -1) goto error;
|
||||
if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(1), context->Dr1 ) == -1) goto error;
|
||||
if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(2), context->Dr2 ) == -1) goto error;
|
||||
if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(3), context->Dr3 ) == -1) goto error;
|
||||
if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(6), context->Dr6 ) == -1) goto error;
|
||||
if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(7), context->Dr7 ) == -1) goto error;
|
||||
}
|
||||
if (flags & CONTEXT_FLOATING_POINT)
|
||||
{
|
||||
/* we can use context->FloatSave directly as it is using the */
|
||||
/* correct structure (the same as fsave/frstor) */
|
||||
if (ptrace( PTRACE_SETFPREGS, pid, 0, &context->FloatSave ) == -1) goto error;
|
||||
context->FloatSave.Cr0NpxState = 0; /* FIXME */
|
||||
}
|
||||
return;
|
||||
error:
|
||||
file_set_error();
|
||||
}
|
||||
|
||||
#else /* linux */
|
||||
#error You must implement get/set_thread_context for your platform
|
||||
#endif /* linux */
|
||||
|
||||
|
||||
/* copy a context structure according to the flags */
|
||||
static void copy_context( CONTEXT *to, CONTEXT *from, int flags )
|
||||
{
|
||||
if (flags & CONTEXT_CONTROL)
|
||||
{
|
||||
to->Ebp = from->Ebp;
|
||||
to->Eip = from->Eip;
|
||||
to->Esp = from->Esp;
|
||||
to->SegCs = from->SegCs;
|
||||
to->SegSs = from->SegSs;
|
||||
to->EFlags = from->EFlags;
|
||||
}
|
||||
if (flags & CONTEXT_INTEGER)
|
||||
{
|
||||
to->Eax = from->Eax;
|
||||
to->Ebx = from->Ebx;
|
||||
to->Ecx = from->Ecx;
|
||||
to->Edx = from->Edx;
|
||||
to->Esi = from->Esi;
|
||||
to->Edi = from->Edi;
|
||||
}
|
||||
if (flags & CONTEXT_SEGMENTS)
|
||||
{
|
||||
to->SegDs = from->SegDs;
|
||||
to->SegEs = from->SegEs;
|
||||
to->SegFs = from->SegFs;
|
||||
to->SegGs = from->SegGs;
|
||||
}
|
||||
if (flags & CONTEXT_DEBUG_REGISTERS)
|
||||
{
|
||||
to->Dr0 = from->Dr0;
|
||||
to->Dr1 = from->Dr1;
|
||||
to->Dr2 = from->Dr2;
|
||||
to->Dr3 = from->Dr3;
|
||||
to->Dr6 = from->Dr6;
|
||||
to->Dr7 = from->Dr7;
|
||||
}
|
||||
if (flags & CONTEXT_FLOATING_POINT)
|
||||
{
|
||||
to->FloatSave = from->FloatSave;
|
||||
}
|
||||
}
|
||||
|
||||
/* retrieve the current context of a thread */
|
||||
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 */
|
||||
{
|
||||
copy_context( &req->context, context, req->flags );
|
||||
}
|
||||
else
|
||||
{
|
||||
suspend_thread( thread, 0 );
|
||||
if (thread->attached) get_thread_context( thread, req->flags, &req->context );
|
||||
else set_error( ERROR_ACCESS_DENIED );
|
||||
resume_thread( thread );
|
||||
}
|
||||
release_object( thread );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* set the current context of a thread */
|
||||
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 */
|
||||
{
|
||||
copy_context( context, &req->context, req->flags );
|
||||
}
|
||||
else
|
||||
{
|
||||
suspend_thread( thread, 0 );
|
||||
if (thread->attached) set_thread_context( thread, req->flags, &req->context );
|
||||
else set_error( ERROR_ACCESS_DENIED );
|
||||
resume_thread( thread );
|
||||
}
|
||||
release_object( thread );
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __i386__ */
|
|
@ -28,8 +28,7 @@ struct debug_event
|
|||
struct thread *debugger; /* debugger thread receiving the event */
|
||||
enum debug_event_state state; /* event state */
|
||||
int status; /* continuation status */
|
||||
int code; /* event code */
|
||||
union debug_event_data data; /* event data */
|
||||
debug_event_t data; /* event data */
|
||||
};
|
||||
|
||||
/* debug context */
|
||||
|
@ -84,21 +83,6 @@ static const struct object_ops debug_ctx_ops =
|
|||
debug_ctx_destroy /* destroy */
|
||||
};
|
||||
|
||||
/* size of the event data */
|
||||
static const int event_sizes[] =
|
||||
{
|
||||
0,
|
||||
sizeof(struct debug_event_exception), /* EXCEPTION_DEBUG_EVENT */
|
||||
sizeof(struct debug_event_create_thread), /* CREATE_THREAD_DEBUG_EVENT */
|
||||
sizeof(struct debug_event_create_process), /* CREATE_PROCESS_DEBUG_EVENT */
|
||||
sizeof(struct debug_event_exit), /* EXIT_THREAD_DEBUG_EVENT */
|
||||
sizeof(struct debug_event_exit), /* EXIT_PROCESS_DEBUG_EVENT */
|
||||
sizeof(struct debug_event_load_dll), /* LOAD_DLL_DEBUG_EVENT */
|
||||
sizeof(struct debug_event_unload_dll), /* UNLOAD_DLL_DEBUG_EVENT */
|
||||
sizeof(struct debug_event_output_string), /* OUTPUT_DEBUG_STRING_EVENT */
|
||||
sizeof(struct debug_event_rip_info) /* RIP_EVENT */
|
||||
};
|
||||
|
||||
|
||||
/* initialise the fields that do not need to be filled by the client */
|
||||
static int fill_debug_event( struct thread *debugger, struct thread *thread,
|
||||
|
@ -107,45 +91,45 @@ static int fill_debug_event( struct thread *debugger, struct thread *thread,
|
|||
int handle;
|
||||
|
||||
/* some events need special handling */
|
||||
switch(event->code)
|
||||
switch(event->data.code)
|
||||
{
|
||||
case CREATE_THREAD_DEBUG_EVENT:
|
||||
if ((event->data.create_thread.handle = alloc_handle( debugger->process, thread,
|
||||
if ((event->data.info.create_thread.handle = alloc_handle( debugger->process, thread,
|
||||
/* documented: THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME */
|
||||
THREAD_ALL_ACCESS, FALSE )) == -1)
|
||||
return 0;
|
||||
break;
|
||||
case CREATE_PROCESS_DEBUG_EVENT:
|
||||
if ((handle = event->data.create_process.file) != -1)
|
||||
if ((handle = event->data.info.create_process.file) != -1)
|
||||
{
|
||||
if ((handle = duplicate_handle( thread->process, handle, debugger->process,
|
||||
GENERIC_READ, FALSE, 0 )) == -1)
|
||||
return 0;
|
||||
event->data.create_process.file = handle;
|
||||
event->data.info.create_process.file = handle;
|
||||
}
|
||||
if ((event->data.create_process.process = alloc_handle( debugger->process, thread->process,
|
||||
if ((event->data.info.create_process.process = alloc_handle( debugger->process, thread->process,
|
||||
/* documented: PROCESS_VM_READ | PROCESS_VM_WRITE */
|
||||
PROCESS_ALL_ACCESS, FALSE )) == -1)
|
||||
{
|
||||
if (handle != -1) close_handle( debugger->process, handle );
|
||||
return 0;
|
||||
}
|
||||
if ((event->data.create_process.thread = alloc_handle( debugger->process, thread,
|
||||
if ((event->data.info.create_process.thread = alloc_handle( debugger->process, thread,
|
||||
/* documented: THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME */
|
||||
THREAD_ALL_ACCESS, FALSE )) == -1)
|
||||
{
|
||||
if (handle != -1) close_handle( debugger->process, handle );
|
||||
close_handle( debugger->process, event->data.create_process.process );
|
||||
close_handle( debugger->process, event->data.info.create_process.process );
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case LOAD_DLL_DEBUG_EVENT:
|
||||
if ((handle = event->data.load_dll.handle) != -1)
|
||||
if ((handle = event->data.info.load_dll.handle) != -1)
|
||||
{
|
||||
if ((handle = duplicate_handle( thread->process, handle, debugger->process,
|
||||
GENERIC_READ, FALSE, 0 )) == -1)
|
||||
return 0;
|
||||
event->data.load_dll.handle = handle;
|
||||
event->data.info.load_dll.handle = handle;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -196,14 +180,14 @@ static void build_wait_debug_reply( struct thread *thread, struct object *obj, i
|
|||
|
||||
event->state = EVENT_SENT;
|
||||
debug_ctx->to_send = event->next;
|
||||
req->code = event->code;
|
||||
req->event.code = event->data.code;
|
||||
req->pid = event->sender->process;
|
||||
req->tid = event->sender;
|
||||
memcpy( req + 1, &event->data, event_sizes[event->code] );
|
||||
memcpy( &req->event, &event->data, sizeof(req->event) );
|
||||
}
|
||||
else /* timeout or error */
|
||||
{
|
||||
req->code = 0;
|
||||
req->event.code = 0;
|
||||
req->pid = 0;
|
||||
req->tid = 0;
|
||||
thread->error = signaled;
|
||||
|
@ -219,8 +203,10 @@ static void build_send_event_reply( struct thread *thread, struct object *obj, i
|
|||
|
||||
req->status = event->status;
|
||||
/* copy the context into the reply */
|
||||
if (event->code == EXCEPTION_DEBUG_EVENT)
|
||||
memcpy( req + 1, &event->data, event_sizes[event->code] );
|
||||
if (event->data.code == EXCEPTION_DEBUG_EVENT)
|
||||
memcpy( &req->event.info.exception.context,
|
||||
&event->data.info.exception.context,
|
||||
sizeof(req->event.info.exception.context) );
|
||||
}
|
||||
|
||||
static void debug_event_dump( struct object *obj, int verbose )
|
||||
|
@ -228,7 +214,7 @@ static void debug_event_dump( struct object *obj, int verbose )
|
|||
struct debug_event *debug_event = (struct debug_event *)obj;
|
||||
assert( obj->ops == &debug_event_ops );
|
||||
fprintf( stderr, "Debug event sender=%p code=%d state=%d\n",
|
||||
debug_event->sender, debug_event->code, debug_event->state );
|
||||
debug_event->sender, debug_event->data.code, debug_event->state );
|
||||
}
|
||||
|
||||
static int debug_event_signaled( struct object *obj, struct thread *thread )
|
||||
|
@ -252,20 +238,20 @@ static void debug_event_destroy( struct object *obj )
|
|||
if (event->state == EVENT_QUEUED)
|
||||
{
|
||||
struct process *debugger = event->debugger->process;
|
||||
switch(event->code)
|
||||
switch(event->data.code)
|
||||
{
|
||||
case CREATE_THREAD_DEBUG_EVENT:
|
||||
close_handle( debugger, event->data.create_thread.handle );
|
||||
close_handle( debugger, event->data.info.create_thread.handle );
|
||||
break;
|
||||
case CREATE_PROCESS_DEBUG_EVENT:
|
||||
if (event->data.create_process.file != -1)
|
||||
close_handle( debugger, event->data.create_process.file );
|
||||
close_handle( debugger, event->data.create_process.thread );
|
||||
close_handle( debugger, event->data.create_process.process );
|
||||
if (event->data.info.create_process.file != -1)
|
||||
close_handle( debugger, event->data.info.create_process.file );
|
||||
close_handle( debugger, event->data.info.create_process.thread );
|
||||
close_handle( debugger, event->data.info.create_process.process );
|
||||
break;
|
||||
case LOAD_DLL_DEBUG_EVENT:
|
||||
if (event->data.load_dll.handle != -1)
|
||||
close_handle( debugger, event->data.load_dll.handle );
|
||||
if (event->data.info.load_dll.handle != -1)
|
||||
close_handle( debugger, event->data.info.load_dll.handle );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -346,7 +332,7 @@ 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 *debugger, struct thread *thread,
|
||||
int code, void *data )
|
||||
debug_event_t *data )
|
||||
{
|
||||
struct debug_ctx *debug_ctx = debugger->debug_ctx;
|
||||
struct debug_event *event;
|
||||
|
@ -360,14 +346,13 @@ static struct debug_event *queue_debug_event( struct thread *debugger, struct th
|
|||
event->next = NULL;
|
||||
event->prev = NULL;
|
||||
event->state = EVENT_QUEUED;
|
||||
event->code = code;
|
||||
event->sender = (struct thread *)grab_object( thread );
|
||||
event->debugger = (struct thread *)grab_object( debugger );
|
||||
memcpy( &event->data, data, event_sizes[code] );
|
||||
memcpy( &event->data, data, sizeof(event->data) );
|
||||
|
||||
if (!fill_debug_event( debugger, thread, event ))
|
||||
{
|
||||
event->code = -1; /* make sure we don't attempt to close handles */
|
||||
event->data.code = -1; /* make sure we don't attempt to close handles */
|
||||
release_object( event );
|
||||
return NULL;
|
||||
}
|
||||
|
@ -377,6 +362,22 @@ static struct debug_event *queue_debug_event( struct thread *debugger, struct th
|
|||
return event;
|
||||
}
|
||||
|
||||
/* 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 )
|
||||
{
|
||||
|
@ -417,13 +418,12 @@ void debug_exit_thread( struct thread *thread, int exit_code )
|
|||
if (debugger) /* being debugged -> send an event to the debugger */
|
||||
{
|
||||
struct debug_event *event;
|
||||
struct debug_event_exit exit;
|
||||
exit.exit_code = exit_code;
|
||||
if (thread->process->running_threads == 1)
|
||||
/* this is the last thread, send an exit process event */
|
||||
event = queue_debug_event( debugger, thread, EXIT_PROCESS_DEBUG_EVENT, &exit );
|
||||
else
|
||||
event = queue_debug_event( debugger, thread, EXIT_THREAD_DEBUG_EVENT, &exit );
|
||||
debug_event_t exit;
|
||||
exit.info.exit.exit_code = exit_code;
|
||||
/* if this is the last thread, send an exit process event */
|
||||
exit.code = ((thread->process->running_threads == 1) ?
|
||||
EXIT_PROCESS_DEBUG_EVENT : EXIT_THREAD_DEBUG_EVENT);
|
||||
event = queue_debug_event( debugger, thread, &exit );
|
||||
if (event) release_object( event );
|
||||
}
|
||||
|
||||
|
@ -441,7 +441,7 @@ DECL_HANDLER(wait_debug_event)
|
|||
{
|
||||
if (!wait_for_debug_event( req->timeout ))
|
||||
{
|
||||
req->code = 0;
|
||||
req->event.code = 0;
|
||||
req->pid = NULL;
|
||||
req->tid = NULL;
|
||||
}
|
||||
|
@ -481,13 +481,13 @@ DECL_HANDLER(send_debug_event)
|
|||
struct thread *debugger = current->process->debugger;
|
||||
struct debug_event *event;
|
||||
|
||||
if ((req->code <= 0) || (req->code > RIP_EVENT))
|
||||
if ((req->event.code <= 0) || (req->event.code > RIP_EVENT))
|
||||
{
|
||||
fatal_protocol_error( current, "send_debug_event: bad code %d\n", req->code );
|
||||
fatal_protocol_error( current, "send_debug_event: bad code %d\n", req->event.code );
|
||||
return;
|
||||
}
|
||||
req->status = 0;
|
||||
if (debugger && ((event = queue_debug_event( debugger, current, req->code, req + 1 ))))
|
||||
if (debugger && ((event = queue_debug_event( debugger, current, &req->event ))))
|
||||
{
|
||||
/* wait for continue_debug_event */
|
||||
struct object *obj = &event->obj;
|
||||
|
|
|
@ -155,6 +155,7 @@ extern int free_console( struct process *process );
|
|||
|
||||
extern int debugger_attach( struct process *process, struct thread *debugger );
|
||||
extern void debug_exit_thread( struct thread *thread, int exit_code );
|
||||
extern CONTEXT *get_debug_context( struct thread *thread );
|
||||
|
||||
/* mapping functions */
|
||||
|
||||
|
|
|
@ -157,6 +157,8 @@ DECL_HANDLER(create_timer);
|
|||
DECL_HANDLER(open_timer);
|
||||
DECL_HANDLER(set_timer);
|
||||
DECL_HANDLER(cancel_timer);
|
||||
DECL_HANDLER(get_thread_context);
|
||||
DECL_HANDLER(set_thread_context);
|
||||
|
||||
#ifdef WANT_REQUEST_HANDLERS
|
||||
|
||||
|
@ -254,6 +256,8 @@ static const struct handler {
|
|||
{ (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) },
|
||||
};
|
||||
#endif /* WANT_REQUEST_HANDLERS */
|
||||
|
||||
|
|
452
server/trace.c
452
server/trace.c
File diff suppressed because it is too large
Load Diff
|
@ -14,7 +14,9 @@
|
|||
"unsigned int" => "%08x",
|
||||
"void*" => "%p",
|
||||
"time_t" => "%ld",
|
||||
"path_t" => "&dump_unicode_string",
|
||||
"path_t" => "&dump_path_t",
|
||||
"debug_event_t" => "&dump_debug_event_t",
|
||||
"CONTEXT" => "&dump_context",
|
||||
"char[1]" => "\\\"%s\\\"",
|
||||
"WCHAR[1]" => "&dump_unicode_string"
|
||||
);
|
||||
|
@ -123,7 +125,7 @@ sub DO_DUMP_FUNC
|
|||
{
|
||||
my $name = shift;
|
||||
my $req = shift;
|
||||
push @trace_lines, "static void dump_${name}_$req( struct ${name}_request *req )\n{\n";
|
||||
push @trace_lines, "static void dump_${name}_$req( const struct ${name}_request *req )\n{\n";
|
||||
while ($#_ >= 0)
|
||||
{
|
||||
my $type = shift;
|
||||
|
@ -134,7 +136,8 @@ sub DO_DUMP_FUNC
|
|||
{
|
||||
my $func = $1;
|
||||
push @trace_lines, " fprintf( stderr, \" $var=\" );\n";
|
||||
push @trace_lines, " $func( req->$var );\n";
|
||||
if ($type =~ /[1]/) { push @trace_lines, " $func( req->$var );\n"; }
|
||||
else { push @trace_lines, " $func( &req->$var );\n"; }
|
||||
push @trace_lines, " fprintf( stderr, \",\" );\n" if ($#_ > 0);
|
||||
}
|
||||
else
|
||||
|
|
Loading…
Reference in New Issue