From 05f0b71bb3694ead30953fbea44b0d245e5ee933 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Thu, 9 Mar 2000 18:18:41 +0000 Subject: [PATCH] Store the list of loaded dlls in the server, and generate debug events internally. --- include/elfdll.h | 2 +- include/module.h | 4 +- include/pe_image.h | 4 +- include/process.h | 2 - include/server.h | 23 ++++++--- loader/elf.c | 7 ++- loader/elfdll.c | 16 +++--- loader/module.c | 53 ++++++-------------- loader/pe_image.c | 35 +++++++------- relay32/builtin32.c | 23 +++++---- scheduler/client.c | 12 ----- scheduler/debugger.c | 37 -------------- scheduler/process.c | 8 --- server/debugger.c | 113 +++++++++++++++++++++++++++---------------- server/object.h | 3 +- server/process.c | 111 +++++++++++++++++++++++++++++++++++++----- server/process.h | 14 +++++- server/ptrace.c | 11 +++-- server/request.c | 15 ------ server/request.h | 7 +-- server/thread.c | 7 ++- server/trace.c | 26 ++++++---- 22 files changed, 292 insertions(+), 241 deletions(-) diff --git a/include/elfdll.h b/include/elfdll.h index 65718aa2bf6..8a39df20d64 100644 --- a/include/elfdll.h +++ b/include/elfdll.h @@ -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); diff --git a/include/module.h b/include/module.h index 8f0fb3ea40b..5a62dc47dbe 100644 --- a/include/module.h +++ b/include/module.h @@ -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); diff --git a/include/pe_image.h b/include/pe_image.h index d4f01943a43..d112bb86eae 100644 --- a/include/pe_image.h +++ b/include/pe_image.h @@ -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); diff --git a/include/process.h b/include/process.h index 045bd78eddb..b32f4c889d3 100644 --- a/include/process.h +++ b/include/process.h @@ -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) { diff --git a/include/server.h b/include/server.h index 5f47c181fcc..ee70bd19363 100644 --- a/include/server.h +++ b/include/server.h @@ -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__ */ diff --git a/loader/elf.c b/loader/elf.c index e35c9d03122..b4936fd5071 100644 --- a/loader/elf.c +++ b/loader/elf.c @@ -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; } diff --git a/loader/elfdll.c b/loader/elfdll.c index 962d5ffcb9e..5426eef32d0 100644 --- a/loader/elfdll.c +++ b/loader/elfdll.c @@ -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; } diff --git a/loader/module.c b/loader/module.c index dd12615512b..ea528f4f769 100644 --- a/loader/module.c +++ b/loader/module.c @@ -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"); diff --git a/loader/pe_image.c b/loader/pe_image.c index 09e98da5e42..2109f745ca9 100644 --- a/loader/pe_image.c +++ b/loader/pe_image.c @@ -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; } diff --git a/relay32/builtin32.c b/relay32/builtin32.c index 71ed8c9865f..65ea369819b 100644 --- a/relay32/builtin32.c +++ b/relay32/builtin32.c @@ -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; } diff --git a/scheduler/client.c b/scheduler/client.c index e78c92d52bd..1215725fbe0 100644 --- a/scheduler/client.c +++ b/scheduler/client.c @@ -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 ); -} diff --git a/scheduler/debugger.c b/scheduler/debugger.c index 4479368165d..d11a0d7552e 100644 --- a/scheduler/debugger.c +++ b/scheduler/debugger.c @@ -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) * diff --git a/scheduler/process.c b/scheduler/process.c index b7dc85ad482..98a5ee435e8 100644 --- a/scheduler/process.c +++ b/scheduler/process.c @@ -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(); diff --git a/server/debugger.c b/server/debugger.c index b62d0d393db..7b7b9b40ea0 100644 --- a/server/debugger.c +++ b/server/debugger.c @@ -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; diff --git a/server/object.h b/server/object.h index 3f87b85bd25..6aa920d7558 100644 --- a/server/object.h +++ b/server/object.h @@ -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 ); diff --git a/server/process.c b/server/process.c index ddd8226f48a..30a9bf5c053 100644 --- a/server/process.c +++ b/server/process.c @@ -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 ); +} diff --git a/server/process.h b/server/process.h index e8e7cc68b54..9f21e05c441 100644 --- a/server/process.h +++ b/server/process.h @@ -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) */ }; diff --git a/server/ptrace.c b/server/ptrace.c index 7567046fb6d..58339f686ef 100644 --- a/server/ptrace.c +++ b/server/ptrace.c @@ -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) */ diff --git a/server/request.c b/server/request.c index 306769259e6..7f67c1b24e0 100644 --- a/server/request.c +++ b/server/request.c @@ -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; - } -} diff --git a/server/request.h b/server/request.h index dc4176a76fb..978b691d2d9 100644 --- a/server/request.h +++ b/server/request.h @@ -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) }, diff --git a/server/thread.c b/server/thread.c index 8f30280e183..cf02b871fa7 100644 --- a/server/thread.c +++ b/server/thread.c @@ -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 */ diff --git a/server/trace.c b/server/trace.c index eaf479353f6..1313c159a73 100644 --- a/server/trace.c +++ b/server/trace.c @@ -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",