Commit 05f0b71b authored by Alexandre Julliard's avatar Alexandre Julliard

Store the list of loaded dlls in the server, and generate debug events

internally.
parent 5fb54566
......@@ -4,7 +4,7 @@
#include "module.h"
#include "windef.h"
WINE_MODREF *ELFDLL_LoadLibraryExA(LPCSTR libname, DWORD flags, DWORD *err);
WINE_MODREF *ELFDLL_LoadLibraryExA(LPCSTR libname, DWORD flags);
HINSTANCE16 ELFDLL_LoadModule16(LPCSTR libname);
void ELFDLL_UnloadLibrary(WINE_MODREF *wm);
......
......@@ -157,7 +157,6 @@ typedef struct _wine_modref
#define WINE_MODREF_PROCESS_ATTACHED 0x00000004
#define WINE_MODREF_LOAD_AS_DATAFILE 0x00000010
#define WINE_MODREF_DONT_RESOLVE_REFS 0x00000020
#define WINE_MODREF_DEBUG_EVENT_SENT 0x00000040
#define WINE_MODREF_MARKER 0x80000000
......@@ -182,7 +181,6 @@ extern BOOL MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved );
extern void MODULE_DllProcessDetach( BOOL bForceDetach, LPVOID lpReserved );
extern void MODULE_DllThreadAttach( LPVOID lpReserved );
extern void MODULE_DllThreadDetach( LPVOID lpReserved );
extern void MODULE_SendLoadDLLEvents( void );
extern WINE_MODREF *MODULE_LoadLibraryExA( LPCSTR libname, HFILE hfile, DWORD flags );
extern BOOL MODULE_FreeLibrary( WINE_MODREF *wm );
extern WINE_MODREF *MODULE_FindModule( LPCSTR path );
......@@ -235,7 +233,7 @@ extern void NE_DllProcessAttach( HMODULE16 hModule );
HGLOBAL16 NE_LoadPEResource( NE_MODULE *pModule, WORD type, LPVOID bits, DWORD size );
/* relay32/builtin.c */
extern WINE_MODREF *BUILTIN32_LoadLibraryExA(LPCSTR name, DWORD flags, DWORD *err);
extern WINE_MODREF *BUILTIN32_LoadLibraryExA(LPCSTR name, DWORD flags);
extern HMODULE16 BUILTIN32_LoadExeModule(void);
extern void BUILTIN32_UnloadLibrary(WINE_MODREF *wm);
......
......@@ -25,7 +25,7 @@ extern BOOL PE_EnumResourceLanguagesA(HMODULE,LPCSTR,LPCSTR,ENUMRESLANGPROCA,LON
extern BOOL PE_EnumResourceLanguagesW(HMODULE,LPCWSTR,LPCWSTR,ENUMRESLANGPROCW,LONG);
extern HRSRC PE_FindResourceExW(struct _wine_modref*,LPCWSTR,LPCWSTR,WORD);
extern DWORD PE_SizeofResource(HMODULE,HRSRC);
extern struct _wine_modref *PE_LoadLibraryExA(LPCSTR, DWORD, DWORD *);
extern struct _wine_modref *PE_LoadLibraryExA(LPCSTR, DWORD);
extern void PE_UnloadLibrary(struct _wine_modref *);
extern HGLOBAL PE_LoadResource(struct _wine_modref *wm,HRSRC);
extern HMODULE PE_LoadImage( HANDLE hFile, LPCSTR filename, WORD *version );
......@@ -64,7 +64,7 @@ typedef struct {
ELF_STDCALL_STUB *stubs;
} ELF_MODREF;
extern struct _wine_modref *ELF_LoadLibraryExA( LPCSTR libname, DWORD flags, DWORD *err);
extern struct _wine_modref *ELF_LoadLibraryExA( LPCSTR libname, DWORD flags);
extern void ELF_UnloadLibrary(struct _wine_modref *);
extern FARPROC ELF_FindExportedFunction(struct _wine_modref *wm, LPCSTR funcName);
......
......@@ -170,8 +170,6 @@ extern void PROCESS_WalkProcess( void );
/* scheduler/debugger.c */
extern DWORD DEBUG_SendExceptionEvent( EXCEPTION_RECORD *rec, BOOL first_chance, CONTEXT *ctx );
extern DWORD DEBUG_SendLoadDLLEvent( HFILE file, HMODULE module, LPSTR *name );
extern DWORD DEBUG_SendUnloadDLLEvent( HMODULE module );
static inline PDB * WINE_UNUSED PROCESS_Current(void)
{
......
......@@ -271,13 +271,22 @@ struct resume_thread_request
};
/* Debugger support: freeze / unfreeze */
struct debugger_request
/* Notify the server that a dll has been loaded */
struct load_dll_request
{
IN int op; /* operation type */
IN int handle; /* file handle */
IN void* base; /* base address */
IN int dbg_offset; /* debug info offset */
IN int dbg_size; /* debug info size */
IN void* name; /* ptr to ptr to name (in process addr space) */
};
enum debugger_op { DEBUGGER_FREEZE_ALL, DEBUGGER_UNFREEZE_ALL };
/* Notify the server that a dll is being unloaded */
struct unload_dll_request
{
IN void* base; /* base address */
};
/* Queue an APC for a thread */
......@@ -1101,7 +1110,8 @@ enum request
REQ_SET_THREAD_INFO,
REQ_SUSPEND_THREAD,
REQ_RESUME_THREAD,
REQ_DEBUGGER,
REQ_LOAD_DLL,
REQ_UNLOAD_DLL,
REQ_QUEUE_APC,
REQ_GET_APCS,
REQ_CLOSE_HANDLE,
......@@ -1186,7 +1196,7 @@ enum request
REQ_NB_REQUESTS
};
#define SERVER_PROTOCOL_VERSION 1
#define SERVER_PROTOCOL_VERSION 2
/* ### make_requests end ### */
/* Everything above this line is generated automatically by tools/make_requests */
......@@ -1250,7 +1260,6 @@ static inline void server_strcpyAtoW( WCHAR *dst, const char *src )
extern int CLIENT_InitServer(void);
extern int CLIENT_BootDone( int debug_level );
extern int CLIENT_IsBootThread(void);
extern int CLIENT_DebuggerRequest( int op );
extern int CLIENT_InitThread(void);
#endif /* __WINE_SERVER__ */
......
......@@ -102,7 +102,7 @@ static WINE_MODREF *ELF_CreateDummyModule( LPCSTR libname, LPCSTR modname )
return wm;
}
WINE_MODREF *ELF_LoadLibraryExA( LPCSTR libname, DWORD flags, DWORD *err)
WINE_MODREF *ELF_LoadLibraryExA( LPCSTR libname, DWORD flags)
{
WINE_MODREF *wm;
char *modname,*s,*t,*x;
......@@ -146,7 +146,7 @@ WINE_MODREF *ELF_LoadLibraryExA( LPCSTR libname, DWORD flags, DWORD *err)
dlhandle = ELFDLL_dlopen(t,RTLD_NOW);
if (!dlhandle) {
HeapFree( GetProcessHeap(), 0, t );
*err = ERROR_FILE_NOT_FOUND;
SetLastError( ERROR_FILE_NOT_FOUND );
return NULL;
}
......@@ -154,7 +154,6 @@ WINE_MODREF *ELF_LoadLibraryExA( LPCSTR libname, DWORD flags, DWORD *err)
wm->binfmt.elf.dlhandle = dlhandle;
SNOOP_RegisterDLL(wm->module,libname,STUBSIZE/sizeof(ELF_STDCALL_STUB));
*err = 0;
return wm;
}
......@@ -271,7 +270,7 @@ void ELF_UnloadLibrary(WINE_MODREF *wm)
#else
WINE_MODREF *ELF_LoadLibraryExA( LPCSTR libname, DWORD flags, DWORD *err)
WINE_MODREF *ELF_LoadLibraryExA( LPCSTR libname, DWORD flags)
{
return NULL;
}
......
......@@ -284,7 +284,7 @@ static HMODULE16 ELFDLL_CreateNEModule(NE_MODULE *ne_image, DWORD size)
*
* Implementation of elf-dll loading for PE modules
*/
WINE_MODREF *ELFDLL_LoadLibraryExA(LPCSTR path, DWORD flags, DWORD *err)
WINE_MODREF *ELFDLL_LoadLibraryExA(LPCSTR path, DWORD flags)
{
LPVOID dlhandle;
struct elfdll_image *image;
......@@ -302,7 +302,7 @@ WINE_MODREF *ELFDLL_LoadLibraryExA(LPCSTR path, DWORD flags, DWORD *err)
if(!dlhandle)
{
WARN("Could not load %s (%s)\n", soname, dlerror());
*err = ERROR_FILE_NOT_FOUND;
SetLastError( ERROR_FILE_NOT_FOUND );
return NULL;
}
......@@ -314,7 +314,7 @@ WINE_MODREF *ELFDLL_LoadLibraryExA(LPCSTR path, DWORD flags, DWORD *err)
{
ERR("Could not get elfdll image descriptor %s (%s)\n", soname, dlerror());
dlclose(dlhandle);
*err = ERROR_BAD_FORMAT;
SetLastError( ERROR_BAD_FORMAT );
return NULL;
}
......@@ -324,7 +324,7 @@ WINE_MODREF *ELFDLL_LoadLibraryExA(LPCSTR path, DWORD flags, DWORD *err)
{
ERR("Could not create win16 dummy module for %s\n", path);
dlclose(dlhandle);
*err = ERROR_OUTOFMEMORY;
SetLastError( ERROR_OUTOFMEMORY );
return NULL;
}
......@@ -336,13 +336,11 @@ WINE_MODREF *ELFDLL_LoadLibraryExA(LPCSTR path, DWORD flags, DWORD *err)
ERR("Could not create WINE_MODREF for %s\n", path);
GLOBAL_FreeBlock((HGLOBAL16)hmod16);
dlclose(dlhandle);
*err = ERROR_OUTOFMEMORY;
SetLastError( ERROR_OUTOFMEMORY );
return NULL;
}
dump_exports(image->pe_module_start);
*err = 0;
return wm;
}
......@@ -374,9 +372,9 @@ HINSTANCE16 ELFDLL_LoadModule16(LPCSTR libname)
* Just put stubs in here.
*/
WINE_MODREF *ELFDLL_LoadLibraryExA(LPCSTR libname, DWORD flags, DWORD *err)
WINE_MODREF *ELFDLL_LoadLibraryExA(LPCSTR libname, DWORD flags)
{
*err = ERROR_FILE_NOT_FOUND;
SetLastError( ERROR_FILE_NOT_FOUND );
return NULL;
}
......
......@@ -34,9 +34,10 @@
#include "callback.h"
#include "loadorder.h"
#include "elfdll.h"
#include "server.h"
DEFAULT_DEBUG_CHANNEL(module)
DECLARE_DEBUG_CHANNEL(win32)
DEFAULT_DEBUG_CHANNEL(module);
DECLARE_DEBUG_CHANNEL(win32);
/*************************************************************************
* MODULE_WalkModref
......@@ -328,29 +329,6 @@ BOOL WINAPI DisableThreadLibraryCalls( HMODULE hModule )
return retval;
}
/*************************************************************************
* MODULE_SendLoadDLLEvents
*
* Sends DEBUG_DLL_LOAD events for all outstanding modules.
*
* NOTE: Assumes that the process critical section is held!
*
*/
void MODULE_SendLoadDLLEvents( void )
{
WINE_MODREF *wm;
for ( wm = PROCESS_Current()->modref_list; wm; wm = wm->next )
{
if ( wm->type != MODULE32_PE ) continue;
if ( wm == PROCESS_Current()->exe_modref ) continue;
if ( wm->flags & WINE_MODREF_DEBUG_EVENT_SENT ) continue;
DEBUG_SendLoadDLLEvent( -1 /*FIXME*/, wm->module, &wm->modname );
wm->flags |= WINE_MODREF_DEBUG_EVENT_SENT;
}
}
/***********************************************************************
* MODULE_CreateDummyModule
......@@ -1352,8 +1330,6 @@ HMODULE WINAPI LoadLibraryExA(LPCSTR libname, HANDLE hfile, DWORD flags)
wm = MODULE_LoadLibraryExA( libname, hfile, flags );
if ( wm )
{
MODULE_SendLoadDLLEvents();
if ( !MODULE_DllProcessAttach( wm, NULL ) )
{
WARN_(module)("Attach failed for module '%s', \n", libname);
......@@ -1381,7 +1357,7 @@ HMODULE WINAPI LoadLibraryExA(LPCSTR libname, HANDLE hfile, DWORD flags)
*/
WINE_MODREF *MODULE_LoadLibraryExA( LPCSTR libname, HFILE hfile, DWORD flags )
{
DWORD err;
DWORD err = GetLastError();
WINE_MODREF *pwm;
int i;
module_loadorder_t *plo;
......@@ -1402,26 +1378,27 @@ WINE_MODREF *MODULE_LoadLibraryExA( LPCSTR libname, HFILE hfile, DWORD flags )
for(i = 0; i < MODULE_LOADORDER_NTYPES; i++)
{
SetLastError( ERROR_FILE_NOT_FOUND );
switch(plo->loadorder[i])
{
case MODULE_LOADORDER_DLL:
TRACE("Trying native dll '%s'\n", libname);
pwm = PE_LoadLibraryExA(libname, flags, &err);
pwm = PE_LoadLibraryExA(libname, flags);
break;
case MODULE_LOADORDER_ELFDLL:
TRACE("Trying elfdll '%s'\n", libname);
pwm = ELFDLL_LoadLibraryExA(libname, flags, &err);
pwm = ELFDLL_LoadLibraryExA(libname, flags);
break;
case MODULE_LOADORDER_SO:
TRACE("Trying so-library '%s'\n", libname);
pwm = ELF_LoadLibraryExA(libname, flags, &err);
pwm = ELF_LoadLibraryExA(libname, flags);
break;
case MODULE_LOADORDER_BI:
TRACE("Trying built-in '%s'\n", libname);
pwm = BUILTIN32_LoadLibraryExA(libname, flags, &err);
pwm = BUILTIN32_LoadLibraryExA(libname, flags);
break;
default:
......@@ -1443,16 +1420,15 @@ WINE_MODREF *MODULE_LoadLibraryExA( LPCSTR libname, HFILE hfile, DWORD flags )
pwm->refCount++;
LeaveCriticalSection(&PROCESS_Current()->crit_section);
SetLastError( err ); /* restore last error */
return pwm;
}
if(err != ERROR_FILE_NOT_FOUND)
if(GetLastError() != ERROR_FILE_NOT_FOUND)
break;
}
WARN("Failed to load module '%s'; error=0x%08lx, \n", libname, err);
SetLastError(err);
WARN("Failed to load module '%s'; error=0x%08lx, \n", libname, GetLastError());
LeaveCriticalSection(&PROCESS_Current()->crit_section);
return NULL;
}
......@@ -1610,8 +1586,11 @@ BOOL MODULE_FreeLibrary( WINE_MODREF *wm )
/* Call process detach notifications */
if ( PROCESS_Current()->free_lib_count <= 1 )
{
struct unload_dll_request *req = get_req_buffer();
MODULE_DllProcessDetach( FALSE, NULL );
DEBUG_SendUnloadDLLEvent( wm->module );
req->base = (void *)wm->module;
server_call_noerr( REQ_UNLOAD_DLL );
}
TRACE("END\n");
......
......@@ -60,6 +60,7 @@
#include "global.h"
#include "task.h"
#include "snoop.h"
#include "server.h"
#include "debugtools.h"
DEFAULT_DEBUG_CHANNEL(win32)
......@@ -886,8 +887,9 @@ WINE_MODREF *PE_CreateModule( HMODULE hModule,
* The PE Library Loader frontend.
* FIXME: handle the flags.
*/
WINE_MODREF *PE_LoadLibraryExA (LPCSTR name, DWORD flags, DWORD *err)
WINE_MODREF *PE_LoadLibraryExA (LPCSTR name, DWORD flags)
{
struct load_dll_request *req = get_req_buffer();
HMODULE hModule32;
HMODULE16 hModule16;
NE_MODULE *pModule;
......@@ -898,33 +900,26 @@ WINE_MODREF *PE_LoadLibraryExA (LPCSTR name, DWORD flags, DWORD *err)
/* Search for and open PE file */
if ( SearchPathA( NULL, name, ".DLL",
sizeof(filename), filename, NULL ) == 0 )
{
*err = ERROR_FILE_NOT_FOUND;
return NULL;
}
sizeof(filename), filename, NULL ) == 0 ) return NULL;
hFile = CreateFileA( filename, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, 0, -1 );
if ( hFile == INVALID_HANDLE_VALUE )
{
*err = ERROR_FILE_NOT_FOUND;
return NULL;
}
if ( hFile == INVALID_HANDLE_VALUE ) return NULL;
/* Load PE module */
hModule32 = PE_LoadImage( hFile, filename, &version );
CloseHandle( hFile );
if (!hModule32)
{
*err = ERROR_OUTOFMEMORY; /* Not entirely right, but good enough */
CloseHandle( hFile );
SetLastError( ERROR_OUTOFMEMORY ); /* Not entirely right, but good enough */
return NULL;
}
/* Create 16-bit dummy module */
if ((hModule16 = MODULE_CreateDummyModule( filename, version )) < 32)
{
*err = (DWORD)hModule16; /* This should give the correct error */
CloseHandle( hFile );
SetLastError( (DWORD)hModule16 ); /* This should give the correct error */
return NULL;
}
pModule = (NE_MODULE *)GlobalLock16( hModule16 );
......@@ -936,14 +931,20 @@ WINE_MODREF *PE_LoadLibraryExA (LPCSTR name, DWORD flags, DWORD *err)
{
ERR( "can't load %s\n", filename );
FreeLibrary16( hModule16 );
*err = ERROR_OUTOFMEMORY;
CloseHandle( hFile );
SetLastError( ERROR_OUTOFMEMORY );
return NULL;
}
if (wm->binfmt.pe.pe_export)
SNOOP_RegisterDLL(wm->module,wm->modname,wm->binfmt.pe.pe_export->NumberOfFunctions);
*err = 0;
req->handle = hFile;
req->base = (void *)hModule32;
req->dbg_offset = 0;
req->dbg_size = 0;
req->name = &wm->modname;
server_call_noerr( REQ_LOAD_DLL );
CloseHandle( hFile );
return wm;
}
......
......@@ -18,6 +18,7 @@
#include "main.h"
#include "snoop.h"
#include "winerror.h"
#include "server.h"
#include "debugtools.h"
DEFAULT_DEBUG_CHANNEL(module);
......@@ -331,8 +332,9 @@ static HMODULE BUILTIN32_DoLoadImage( const BUILTIN32_DESCRIPTOR *descr )
* Partly copied from the original PE_ version.
*
*/
WINE_MODREF *BUILTIN32_LoadLibraryExA(LPCSTR path, DWORD flags, DWORD *err)
WINE_MODREF *BUILTIN32_LoadLibraryExA(LPCSTR path, DWORD flags)
{
struct load_dll_request *req = get_req_buffer();
HMODULE16 hModule16;
NE_MODULE *pModule;
WINE_MODREF *wm;
......@@ -352,25 +354,21 @@ WINE_MODREF *BUILTIN32_LoadLibraryExA(LPCSTR path, DWORD flags, DWORD *err)
if (i == nb_dlls)
{
*err = ERROR_FILE_NOT_FOUND;
SetLastError( ERROR_FILE_NOT_FOUND );
return NULL;
}
/* Load built-in module */
if (!dll_modules[i])
{
if (!(dll_modules[i] = BUILTIN32_DoLoadImage( builtin_dlls[i] )))
{
*err = ERROR_FILE_NOT_FOUND;
return NULL;
}
if (!(dll_modules[i] = BUILTIN32_DoLoadImage( builtin_dlls[i] ))) return NULL;
}
else BUILTIN32_WarnSecondInstance( builtin_dlls[i]->name );
/* Create 16-bit dummy module */
if ((hModule16 = MODULE_CreateDummyModule( dllname, 0 )) < 32)
{
*err = (DWORD)hModule16;
SetLastError( (DWORD)hModule16 );
return NULL; /* FIXME: Should unload the builtin module */
}
......@@ -383,14 +381,19 @@ WINE_MODREF *BUILTIN32_LoadLibraryExA(LPCSTR path, DWORD flags, DWORD *err)
{
ERR( "can't load %s\n", path );
FreeLibrary16( hModule16 ); /* FIXME: Should unload the builtin module */
*err = ERROR_OUTOFMEMORY;
SetLastError( ERROR_OUTOFMEMORY );
return NULL;
}
if (wm->binfmt.pe.pe_export)
SNOOP_RegisterDLL(wm->module,wm->modname,wm->binfmt.pe.pe_export->NumberOfFunctions);
*err = 0;
req->handle = -1;
req->base = (void *)pModule->module32;
req->dbg_offset = 0;
req->dbg_size = 0;
req->name = &wm->modname;
server_call_noerr( REQ_LOAD_DLL );
return wm;
}
......
......@@ -505,15 +505,3 @@ int CLIENT_IsBootThread(void)
{
return (GetCurrentThreadId() == (DWORD)boot_thread_id);
}
/***********************************************************************
* CLIENT_DebuggerRequest
*
* Send a debugger support request. Return 0 if OK.
*/
int CLIENT_DebuggerRequest( int op )
{
struct debugger_request *req = get_req_buffer();
req->op = op;
return server_call( REQ_DEBUGGER );
}
......@@ -40,43 +40,6 @@ DWORD DEBUG_SendExceptionEvent( EXCEPTION_RECORD *rec, BOOL first_chance, CONTEX
}
/**********************************************************************
* DEBUG_SendLoadDLLEvent
*
* Send an LOAD_DLL_DEBUG_EVENT event to the current process debugger.
*/
DWORD DEBUG_SendLoadDLLEvent( HFILE file, HMODULE module, LPSTR *name )
{
struct send_debug_event_request *req = get_req_buffer();
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;
server_call_noerr( REQ_SEND_DEBUG_EVENT );
return req->status;
}
/**********************************************************************
* DEBUG_SendUnloadDLLEvent
*
* Send an UNLOAD_DLL_DEBUG_EVENT event to the current process debugger.
*/
DWORD DEBUG_SendUnloadDLLEvent( HMODULE module )
{
struct send_debug_event_request *req = get_req_buffer();
req->event.code = UNLOAD_DLL_DEBUG_EVENT;
req->event.info.unload_dll.base = (void *)module;
server_call_noerr( REQ_SEND_DEBUG_EVENT );
return req->status;
}
/******************************************************************************
* WaitForDebugEvent (KERNEL32.720)
*
......
......@@ -458,14 +458,6 @@ void PROCESS_Start(void)
server_call( REQ_INIT_PROCESS_DONE );
debugged = req->debugged;
/* Send all required start-up debugger events */
if (type == PROC_WIN32 && debugged)
{
EnterCriticalSection( &pdb->crit_section );
MODULE_SendLoadDLLEvents();
LeaveCriticalSection( &pdb->crit_section );
}
if ( (pdb->flags & PDB32_CONSOLE_PROC) || (pdb->flags & PDB32_DOS_PROC) )
AllocConsole();
......
......@@ -84,72 +84,85 @@ 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 thread *debugger, struct thread *thread,
struct debug_event *event )
static int fill_debug_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:
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)
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.teb = thread->teb;
event->data.info.create_thread.start = thread->entry;
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:
if ((handle = alloc_handle( debugger->process, thread->process,
/* documented: PROCESS_VM_READ | PROCESS_VM_WRITE */
PROCESS_ALL_ACCESS, FALSE )) == -1)
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;
if ((handle = alloc_handle( debugger->process, thread,
/* documented: THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME */
THREAD_ALL_ACCESS, FALSE )) == -1)
/* documented: THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME */
if ((handle = alloc_handle( debugger, thread, THREAD_ALL_ACCESS, FALSE )) == -1)
{
close_handle( debugger->process, event->data.info.create_process.process );
close_handle( debugger, event->data.info.create_process.process );
return 0;
}
event->data.info.create_process.thread = handle;
handle = -1;
if (thread->process->exe_file &&
((handle = alloc_handle( debugger->process, thread->process->exe_file,
/* the doc says write access too, but this doesn't seem a good idea */
GENERIC_READ, FALSE )) == -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->process, event->data.info.create_process.process );
close_handle( debugger->process, event->data.info.create_process.thread );
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 = thread->process->module;
event->data.info.create_process.base = process->exe.base;
event->data.info.create_process.start = thread->entry;
event->data.info.create_process.dbg_offset = 0;
event->data.info.create_process.dbg_size = 0;
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:
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.info.load_dll.handle = handle;
}
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 EXCEPTION_DEBUG_EVENT:
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;
......@@ -333,7 +346,6 @@ static int continue_debug_event( struct process *process, struct thread *thread,
{
if (event == debug_ctx->to_send) goto error;
if (event->sender == thread) break;
event = event->next;
}
if (!event) goto error;
......@@ -351,7 +363,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 *thread, int code,
static struct debug_event *queue_debug_event( struct thread *thread, int code, void *arg,
debug_event_t *data )
{
struct thread *debugger = thread->process->debugger;
......@@ -372,7 +384,7 @@ static struct debug_event *queue_debug_event( struct thread *thread, int code,
if (data) memcpy( &event->data, data, sizeof(event->data) );
event->data.code = code;
if (!fill_debug_event( debugger, thread, event ))
if (!fill_debug_event( event, arg ))
{
event->data.code = -1; /* make sure we don't attempt to close handles */
release_object( event );
......@@ -385,15 +397,35 @@ static struct debug_event *queue_debug_event( struct thread *thread, int code,
}
/* generate a debug event from inside the server and queue it */
void generate_debug_event( struct thread *thread, int code )
void generate_debug_event( struct thread *thread, int code, void *arg )
{
if (thread->process->debugger)
{
struct debug_event *event = queue_debug_event( thread, code, NULL );
struct debug_event *event = queue_debug_event( thread, code, arg, NULL );
if (event) release_object( event );
}
}
/* generate all startup events of a given process */
void generate_startup_debug_events( struct process *process )
{
struct process_dll *dll;
struct thread *thread = process->thread_list;
/* generate creation events */
generate_debug_event( thread, CREATE_PROCESS_DEBUG_EVENT, process );
while ((thread = thread->next))
generate_debug_event( thread, CREATE_THREAD_DEBUG_EVENT, thread );
/* generate dll events (in loading order, i.e. reverse list order) */
for (dll = &process->exe; dll->next; dll = dll->next);
while (dll != &process->exe)
{
generate_debug_event( process->thread_list, LOAD_DLL_DEBUG_EVENT, dll );
dll = dll->prev;
}
}
/* return a pointer to the context in case the thread is inside an exception event */
CONTEXT *get_debug_context( struct thread *thread )
{
......@@ -487,10 +519,8 @@ DECL_HANDLER(debug_process)
if (!process) return;
if (debugger_attach( process, current ))
{
struct thread *thread = process->thread_list;
generate_debug_event( thread, CREATE_PROCESS_DEBUG_EVENT );
while ((thread = thread->next)) generate_debug_event( thread, CREATE_THREAD_DEBUG_EVENT );
/* FIXME: load dll + breakpoint exception events */
generate_startup_debug_events( process );
/* FIXME: breakpoint exception event */
}
release_object( process );
}
......@@ -507,7 +537,8 @@ DECL_HANDLER(send_debug_event)
return;
}
req->status = 0;
if (current->process->debugger && ((event = queue_debug_event( current, code, &req->event ))))
if (current->process->debugger && ((event = queue_debug_event( current, code,
NULL, &req->event ))))
{
/* wait for continue_debug_event */
struct object *obj = &event->obj;
......
......@@ -154,7 +154,8 @@ extern int free_console( struct process *process );
/* debugger functions */
extern int debugger_attach( struct process *process, struct thread *debugger );
extern void generate_debug_event( struct thread *thread, int code );
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 );
......
......@@ -143,7 +143,6 @@ struct thread *create_process( int fd, struct process *parent,
process->prev = NULL;
process->thread_list = NULL;
process->debugger = NULL;
process->exe_file = NULL;
process->handles = NULL;
process->exit_code = STILL_ACTIVE;
process->running_threads = 0;
......@@ -157,6 +156,11 @@ struct thread *create_process( int fd, struct process *parent,
process->info = NULL;
process->ldt_copy = NULL;
process->ldt_flags = NULL;
process->exe.next = NULL;
process->exe.prev = NULL;
process->exe.file = NULL;
process->exe.dbg_offset = 0;
process->exe.dbg_size = 0;
gettimeofday( &process->start_time, NULL );
if ((process->next = first_process) != NULL) process->next->prev = process;
first_process = process;
......@@ -176,7 +180,7 @@ struct thread *create_process( int fd, struct process *parent,
/* retrieve the main exe file */
if (process->info->exe_file != -1)
{
if (!(process->exe_file = get_file_obj( parent, process->info->exe_file,
if (!(process->exe.file = get_file_obj( parent, process->info->exe_file,
GENERIC_READ ))) goto error;
process->info->exe_file = -1;
}
......@@ -225,7 +229,7 @@ static void process_destroy( struct object *obj )
else first_process = process->next;
if (process->info) free( process->info );
if (process->init_event) release_object( process->init_event );
if (process->exe_file) release_object( process->exe_file );
if (process->exe.file) release_object( process->exe.file );
}
/* dump a process on stdout for debugging purposes */
......@@ -263,17 +267,68 @@ struct process *get_process_from_handle( int handle, unsigned int access )
access, &process_ops );
}
/* add a dll to a process list */
static struct process_dll *process_load_dll( struct process *process, struct file *file,
void *base )
{
struct process_dll *dll;
/* make sure we don't already have one with the same base address */
for (dll = process->exe.next; dll; dll = dll->next) if (dll->base == base)
{
set_error( STATUS_INVALID_PARAMETER );
return NULL;
}
if ((dll = mem_alloc( sizeof(*dll) )))
{
dll->prev = &process->exe;
dll->file = NULL;
dll->base = base;
if (file) dll->file = (struct file *)grab_object( file );
if ((dll->next = process->exe.next)) dll->next->prev = dll;
process->exe.next = dll;
}
return dll;
}
/* remove a dll from a process list */
static void process_unload_dll( struct process *process, void *base )
{
struct process_dll *dll;
for (dll = process->exe.next; dll; dll = dll->next)
{
if (dll->base == base)
{
if (dll->file) release_object( dll->file );
if (dll->next) dll->next->prev = dll->prev;
if (dll->prev) dll->prev->next = dll->next;
free( dll );
generate_debug_event( current, UNLOAD_DLL_DEBUG_EVENT, base );
return;
}
}
set_error( STATUS_INVALID_PARAMETER );
}
/* a process has been killed (i.e. its last thread died) */
static void process_killed( struct process *process, int exit_code )
static void process_killed( struct process *process )
{
assert( !process->thread_list );
process->exit_code = exit_code;
gettimeofday( &process->end_time, NULL );
release_object( process->handles );
process->handles = NULL;
free_console( process );
if (process->exe_file) release_object( process->exe_file );
process->exe_file = NULL;
while (process->exe.next)
{
struct process_dll *dll = process->exe.next;
process->exe.next = dll->next;
if (dll->file) release_object( dll->file );
free( dll );
}
if (process->exe.file) release_object( process->exe.file );
process->exe.file = NULL;
wake_up( &process->obj, 0 );
if (!--running_processes)
{
......@@ -308,8 +363,11 @@ void remove_process_thread( struct process *process, struct thread *thread )
if (!--process->running_threads)
{
/* we have removed the last running thread, exit the process */
process_killed( process, thread->exit_code );
process->exit_code = thread->exit_code;
generate_debug_event( thread, EXIT_PROCESS_DEBUG_EVENT, process );
process_killed( process );
}
else generate_debug_event( thread, EXIT_THREAD_DEBUG_EVENT, thread );
release_object( thread );
}
......@@ -580,8 +638,8 @@ DECL_HANDLER(init_process)
req->cmd_show = info->cmd_show;
req->env_ptr = info->env_ptr;
strcpy( req->cmdline, info->cmdline );
if (current->process->exe_file)
req->exe_file = alloc_handle( current->process, current->process->exe_file,
if (current->process->exe.file)
req->exe_file = alloc_handle( current->process, current->process->exe.file,
GENERIC_READ, 0 );
free( info );
}
......@@ -595,9 +653,9 @@ DECL_HANDLER(init_process_done)
fatal_protocol_error( current, "init_process_done: no event\n" );
return;
}
current->entry = req->entry;
process->module = req->module;
generate_debug_event( current, CREATE_PROCESS_DEBUG_EVENT );
current->entry = req->entry;
process->exe.base = req->module;
generate_startup_debug_events( current->process );
set_event( process->init_event );
release_object( process->init_event );
process->init_event = NULL;
......@@ -678,3 +736,30 @@ DECL_HANDLER(write_process_memory)
release_object( process );
}
}
/* notify the server that a dll has been loaded */
DECL_HANDLER(load_dll)
{
struct process_dll *dll;
struct file *file = NULL;
if ((req->handle != -1) &&
!(file = get_file_obj( current->process, req->handle, GENERIC_READ ))) return;
if ((dll = process_load_dll( current->process, file, req->base )))
{
dll->dbg_offset = req->dbg_offset;
dll->dbg_size = req->dbg_size;
dll->name = req->name;
/* only generate event if initialization is done */
if (!current->process->init_event)
generate_debug_event( current, LOAD_DLL_DEBUG_EVENT, dll );
}
if (file) release_object( file );
}
/* notify the server that a dll is being unloaded */
DECL_HANDLER(unload_dll)
{
process_unload_dll( current->process, req->base );
}
......@@ -15,6 +15,17 @@
/* process structures */
struct process_dll
{
struct process_dll *next; /* per-process dll list */
struct process_dll *prev;
struct file *file; /* dll file */
void *base; /* dll base address (in process addr space) */
void *name; /* ptr to ptr to name (in process addr space) */
int dbg_offset; /* debug info offset */
int dbg_size; /* debug info size */
};
struct process
{
struct object obj; /* object header */
......@@ -22,7 +33,6 @@ struct process
struct process *prev;
struct thread *thread_list; /* head of the thread list */
struct thread *debugger; /* thread debugging this process */
struct file *exe_file; /* main exe file */
struct object *handles; /* handle entries */
int exit_code; /* process exit code */
int running_threads; /* number of threads running in this process */
......@@ -35,9 +45,9 @@ struct process
struct object *console_in; /* console input */
struct object *console_out; /* console output */
struct event *init_event; /* event for init done */
struct process_dll exe; /* main exe file */
void *ldt_copy; /* pointer to LDT copy in client addr space */
void *ldt_flags; /* pointer to LDT flags in client addr space */
void *module; /* main module base address */
struct new_process_request *info; /* startup info (freed after startup) */
};
......
......@@ -120,15 +120,20 @@ static int attach_thread( struct thread *thread )
void detach_thread( struct thread *thread )
{
if (!thread->unix_pid) return;
kill( thread->unix_pid, SIGTERM );
if (thread->suspend + thread->process->suspend) continue_thread( thread );
if (thread->attached)
{
wait4_thread( thread, SIGTERM );
/* make sure it is stopped */
if (!(thread->suspend + thread->process->suspend)) stop_thread( thread );
kill( thread->unix_pid, SIGTERM );
if (debug_level) fprintf( stderr, "%08x: *detached*\n", (unsigned int)thread );
ptrace( PTRACE_DETACH, thread->unix_pid, 1, SIGTERM );
thread->attached = 0;
}
else
{
kill( thread->unix_pid, SIGTERM );
if (thread->suspend + thread->process->suspend) continue_thread( thread );
}
}
/* stop a thread (at the Unix level) */
......
......@@ -383,18 +383,3 @@ void lock_master_socket( int locked )
{
set_select_events( &master_socket->obj, locked ? 0 : POLLIN );
}
/* debugger support operations */
DECL_HANDLER(debugger)
{
switch ( req->op )
{
case DEBUGGER_FREEZE_ALL:
suspend_all_threads();
break;
case DEBUGGER_UNFREEZE_ALL:
resume_all_threads();
break;
}
}
......@@ -36,7 +36,6 @@ 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_kill( struct thread *thread );
extern void trace_reply( struct thread *thread );
/* get the request buffer */
......@@ -85,7 +84,8 @@ DECL_HANDLER(get_thread_info);
DECL_HANDLER(set_thread_info);
DECL_HANDLER(suspend_thread);
DECL_HANDLER(resume_thread);
DECL_HANDLER(debugger);
DECL_HANDLER(load_dll);
DECL_HANDLER(unload_dll);
DECL_HANDLER(queue_apc);
DECL_HANDLER(get_apcs);
DECL_HANDLER(close_handle);
......@@ -189,7 +189,8 @@ static const struct handler {
{ (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_debugger, sizeof(struct debugger_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) },
......
......@@ -563,10 +563,9 @@ void kill_thread( struct thread *thread, int exit_code )
thread->state = TERMINATED;
thread->exit_code = exit_code;
if (current == thread) current = NULL;
if (debug_level) trace_kill( thread );
if (debug_level)
fprintf( stderr,"%08x: *killed* exit_code=%d\n", (unsigned int)thread, exit_code );
if (thread->wait) end_wait( thread );
generate_debug_event( thread, (thread->process->running_threads == 1) ?
EXIT_PROCESS_DEBUG_EVENT : EXIT_THREAD_DEBUG_EVENT );
debug_exit_thread( thread );
abandon_mutexes( thread );
remove_process_thread( thread->process, thread );
......@@ -633,7 +632,7 @@ DECL_HANDLER(init_thread)
current->entry = req->entry;
if (current->suspend + current->process->suspend > 0) stop_thread( current );
if (current->process->running_threads > 1)
generate_debug_event( current, CREATE_THREAD_DEBUG_EVENT );
generate_debug_event( current, CREATE_THREAD_DEBUG_EVENT, current );
}
/* terminate a thread */
......
......@@ -361,9 +361,18 @@ static void dump_resume_thread_reply( const struct resume_thread_request *req )
fprintf( stderr, " count=%d", req->count );
}
static void dump_debugger_request( const struct debugger_request *req )
static void dump_load_dll_request( const struct load_dll_request *req )
{
fprintf( stderr, " op=%d", req->op );
fprintf( stderr, " handle=%d,", req->handle );
fprintf( stderr, " base=%p,", req->base );
fprintf( stderr, " dbg_offset=%d,", req->dbg_offset );
fprintf( stderr, " dbg_size=%d,", req->dbg_size );
fprintf( stderr, " name=%p", req->name );
}
static void dump_unload_dll_request( const struct unload_dll_request *req )
{
fprintf( stderr, " base=%p", req->base );
}
static void dump_queue_apc_request( const struct queue_apc_request *req )
......@@ -1247,7 +1256,8 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_set_thread_info_request,
(dump_func)dump_suspend_thread_request,
(dump_func)dump_resume_thread_request,
(dump_func)dump_debugger_request,
(dump_func)dump_load_dll_request,
(dump_func)dump_unload_dll_request,
(dump_func)dump_queue_apc_request,
(dump_func)dump_get_apcs_request,
(dump_func)dump_close_handle_request,
......@@ -1349,6 +1359,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_resume_thread_reply,
(dump_func)0,
(dump_func)0,
(dump_func)0,
(dump_func)dump_get_apcs_reply,
(dump_func)0,
(dump_func)dump_get_handle_info_reply,
......@@ -1447,7 +1458,8 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
"set_thread_info",
"suspend_thread",
"resume_thread",
"debugger",
"load_dll",
"unload_dll",
"queue_apc",
"get_apcs",
"close_handle",
......@@ -1548,12 +1560,6 @@ void trace_request( enum request req, int fd )
else fprintf( stderr, " )\n" );
}
void trace_kill( struct thread *thread )
{
fprintf( stderr,"%08x: *killed* exit_code=%d\n",
(unsigned int)thread, thread->exit_code );
}
void trace_reply( struct thread *thread )
{
fprintf( stderr, "%08x: %s() = %x",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment