Added Get/SetThreadContext support through the server.

This commit is contained in:
Alexandre Julliard 2000-01-20 18:59:03 +00:00 committed by Alexandre Julliard
parent 681c75bf17
commit 3e2517caa7
10 changed files with 858 additions and 441 deletions

View File

@ -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
{
@ -707,92 +787,18 @@ struct next_process_request
/* Wait for a debug event */
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; */
IN int timeout; /* timeout in ms */
OUT void* pid; /* process id */
OUT void* tid; /* thread id */
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;
OUT int status; /* event continuation status */
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
};

View File

@ -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));

View File

@ -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;
}

View File

@ -8,6 +8,7 @@ MODULE = server
C_SRCS = \
change.c \
console.c \
context_i386.c \
debugger.c \
device.c \
event.c \

264
server/context_i386.c Normal file
View File

@ -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, &regs ) == -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, &regs ) == -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, &regs ) == -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__ */

View File

@ -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,9 +441,9 @@ DECL_HANDLER(wait_debug_event)
{
if (!wait_for_debug_event( req->timeout ))
{
req->code = 0;
req->pid = NULL;
req->tid = NULL;
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;

View File

@ -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 */

View File

@ -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 */

File diff suppressed because it is too large Load Diff

View File

@ -8,15 +8,17 @@
%formats =
(
"int" => "%d",
"long" => "%ld",
"char" => "%c",
"unsigned int" => "%08x",
"void*" => "%p",
"time_t" => "%ld",
"path_t" => "&dump_unicode_string",
"char[1]" => "\\\"%s\\\"",
"WCHAR[1]" => "&dump_unicode_string"
"int" => "%d",
"long" => "%ld",
"char" => "%c",
"unsigned int" => "%08x",
"void*" => "%p",
"time_t" => "%ld",
"path_t" => "&dump_path_t",
"debug_event_t" => "&dump_debug_event_t",
"CONTEXT" => "&dump_context",
"char[1]" => "\\\"%s\\\"",
"WCHAR[1]" => "&dump_unicode_string"
);
my @requests = ();
@ -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