Added support for installing an error callback when expecting an X11
[wine] / dlls / kernel / debugger.c
1 /*
2  * Win32 debugger functions
3  *
4  * Copyright (C) 1999 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <stdio.h>
22 #include <string.h>
23
24 #include "winerror.h"
25 #include "wine/winbase16.h"
26 #include "wine/server.h"
27 #include "stackframe.h"
28 #include "wine/debug.h"
29
30 WINE_DEFAULT_DEBUG_CHANNEL(debugstr);
31
32
33 /******************************************************************************
34  *           WaitForDebugEvent   (KERNEL32.@)
35  *
36  *  Waits for a debugging event to occur in a process being debugged before
37  *  filling out the debug event structure.
38  *
39  * RETURNS
40  *
41  *  Returns true if a debug event occurred and false if the call timed out.
42  */
43 BOOL WINAPI WaitForDebugEvent(
44     LPDEBUG_EVENT event,   /* [out] Address of structure for event information. */
45     DWORD         timeout) /* [in] Number of milliseconds to wait for event. */
46 {
47     BOOL ret;
48     DWORD res;
49
50     for (;;)
51     {
52         HANDLE wait = 0;
53         debug_event_t data;
54         SERVER_START_REQ( wait_debug_event )
55         {
56             req->get_handle = (timeout != 0);
57             wine_server_set_reply( req, &data, sizeof(data) );
58             if (!(ret = !wine_server_call_err( req ))) goto done;
59
60             if (!wine_server_reply_size(reply))  /* timeout */
61             {
62                 wait = reply->wait;
63                 ret = FALSE;
64                 goto done;
65             }
66             event->dwDebugEventCode = data.code;
67             event->dwProcessId      = (DWORD)reply->pid;
68             event->dwThreadId       = (DWORD)reply->tid;
69             switch(data.code)
70             {
71             case EXCEPTION_DEBUG_EVENT:
72                 event->u.Exception.ExceptionRecord = data.info.exception.record;
73                 event->u.Exception.dwFirstChance   = data.info.exception.first;
74                 break;
75             case CREATE_THREAD_DEBUG_EVENT:
76                 event->u.CreateThread.hThread           = data.info.create_thread.handle;
77                 event->u.CreateThread.lpThreadLocalBase = data.info.create_thread.teb;
78                 event->u.CreateThread.lpStartAddress    = data.info.create_thread.start;
79                 break;
80             case CREATE_PROCESS_DEBUG_EVENT:
81                 event->u.CreateProcessInfo.hFile                 = data.info.create_process.file;
82                 event->u.CreateProcessInfo.hProcess              = data.info.create_process.process;
83                 event->u.CreateProcessInfo.hThread               = data.info.create_process.thread;
84                 event->u.CreateProcessInfo.lpBaseOfImage         = data.info.create_process.base;
85                 event->u.CreateProcessInfo.dwDebugInfoFileOffset = data.info.create_process.dbg_offset;
86                 event->u.CreateProcessInfo.nDebugInfoSize        = data.info.create_process.dbg_size;
87                 event->u.CreateProcessInfo.lpThreadLocalBase     = data.info.create_process.teb;
88                 event->u.CreateProcessInfo.lpStartAddress        = data.info.create_process.start;
89                 event->u.CreateProcessInfo.lpImageName           = data.info.create_process.name;
90                 event->u.CreateProcessInfo.fUnicode              = data.info.create_process.unicode;
91                 if (data.info.create_process.file == -1) event->u.CreateProcessInfo.hFile = 0;
92                 break;
93             case EXIT_THREAD_DEBUG_EVENT:
94                 event->u.ExitThread.dwExitCode = data.info.exit.exit_code;
95                 break;
96             case EXIT_PROCESS_DEBUG_EVENT:
97                 event->u.ExitProcess.dwExitCode = data.info.exit.exit_code;
98                 break;
99             case LOAD_DLL_DEBUG_EVENT:
100                 event->u.LoadDll.hFile                 = data.info.load_dll.handle;
101                 event->u.LoadDll.lpBaseOfDll           = data.info.load_dll.base;
102                 event->u.LoadDll.dwDebugInfoFileOffset = data.info.load_dll.dbg_offset;
103                 event->u.LoadDll.nDebugInfoSize        = data.info.load_dll.dbg_size;
104                 event->u.LoadDll.lpImageName           = data.info.load_dll.name;
105                 event->u.LoadDll.fUnicode              = data.info.load_dll.unicode;
106                 if (data.info.load_dll.handle == -1) event->u.LoadDll.hFile = 0;
107                 break;
108             case UNLOAD_DLL_DEBUG_EVENT:
109                 event->u.UnloadDll.lpBaseOfDll = data.info.unload_dll.base;
110                 break;
111             case OUTPUT_DEBUG_STRING_EVENT:
112                 event->u.DebugString.lpDebugStringData  = data.info.output_string.string;
113                 event->u.DebugString.fUnicode           = data.info.output_string.unicode;
114                 event->u.DebugString.nDebugStringLength = data.info.output_string.length;
115                 break;
116             case RIP_EVENT:
117                 event->u.RipInfo.dwError = data.info.rip_info.error;
118                 event->u.RipInfo.dwType  = data.info.rip_info.type;
119                 break;
120             }
121         done:
122             /* nothing */ ;
123         }
124         SERVER_END_REQ;
125         if (ret) return TRUE;
126         if (!wait) break;
127         res = WaitForSingleObject( wait, timeout );
128         CloseHandle( wait );
129         if (res != STATUS_WAIT_0) break;
130     }
131     SetLastError( ERROR_SEM_TIMEOUT );
132     return FALSE;
133 }
134
135
136 /**********************************************************************
137  *           ContinueDebugEvent   (KERNEL32.@)
138  *
139  *  Enables a thread that previously produced a debug event to continue.
140  *
141  * RETURNS
142  *
143  *  True if the debugger is listed as the processes owner and the process
144  *  and thread are valid.
145  */
146 BOOL WINAPI ContinueDebugEvent(
147     DWORD pid,    /* [in] The id of the process to continue. */
148     DWORD tid,    /* [in] The id of the thread to continue. */
149     DWORD status) /* [in] The rule to apply to unhandled exeptions. */
150 {
151     BOOL ret;
152     SERVER_START_REQ( continue_debug_event )
153     {
154         req->pid    = (void *)pid;
155         req->tid    = (void *)tid;
156         req->status = status;
157         ret = !wine_server_call_err( req );
158     }
159     SERVER_END_REQ;
160     return ret;
161 }
162
163
164 /**********************************************************************
165  *           DebugActiveProcess   (KERNEL32.@)
166  *
167  *  Attempts to attach the debugger to a process.
168  *
169  * RETURNS
170  *
171  *  True if the debugger was attached to process.
172  */
173 BOOL WINAPI DebugActiveProcess(
174     DWORD pid) /* [in] The process to be debugged. */
175 {
176     BOOL ret;
177     SERVER_START_REQ( debug_process )
178     {
179         req->pid = (void *)pid;
180         req->attach = 1;
181         ret = !wine_server_call_err( req );
182     }
183     SERVER_END_REQ;
184     return ret;
185 }
186
187 /**********************************************************************
188  *           DebugActiveProcessStop   (KERNEL32.@)
189  *
190  *  Attempts to detach the debugger from a process.
191  *
192  * RETURNS
193  *
194  *  True if the debugger was detached from the process.
195  */
196 BOOL WINAPI DebugActiveProcessStop(
197     DWORD pid) /* [in] The process to be detached. */
198 {
199     BOOL ret;
200     SERVER_START_REQ( debug_process )
201     {
202         req->pid = (void *)pid;
203         req->attach = 0;
204         ret = !wine_server_call_err( req );
205     }
206     SERVER_END_REQ;
207     return ret;
208 }
209
210
211 /***********************************************************************
212  *           OutputDebugStringA   (KERNEL32.@)
213  *
214  *  Output by an application of a unicode string to a debugger (if attached)
215  *  and program log.
216  */
217 void WINAPI OutputDebugStringA(
218     LPCSTR str) /* [in] The message to be logged and given to the debugger. */
219 {
220     SERVER_START_REQ( output_debug_string )
221     {
222         req->string  = (void *)str;
223         req->unicode = 0;
224         req->length  = strlen(str) + 1;
225         wine_server_call( req );
226     }
227     SERVER_END_REQ;
228     WARN("%s\n", str);
229 }
230
231
232 /***********************************************************************
233  *           OutputDebugStringW   (KERNEL32.@)
234  *
235  *  Output by an appliccation of a unicode string to a debugger (if attached)
236  *  and program log.
237  */
238 void WINAPI OutputDebugStringW(
239     LPCWSTR str) /* [in] The message to be logged and given to the debugger. */
240 {
241     SERVER_START_REQ( output_debug_string )
242     {
243         req->string  = (void *)str;
244         req->unicode = 1;
245         req->length  = (lstrlenW(str) + 1) * sizeof(WCHAR);
246         wine_server_call( req );
247     }
248     SERVER_END_REQ;
249     WARN("%s\n", debugstr_w(str));
250 }
251
252
253 /***********************************************************************
254  *           OutputDebugString   (KERNEL.115)
255  *
256  *  Output by a 16 bit application of an ascii string to a debugger (if attached)
257  *  and program log.
258  */
259 void WINAPI OutputDebugString16(
260     LPCSTR str) /* [in] The message to be logged and given to the debugger. */
261 {
262     OutputDebugStringA( str );
263 }
264
265
266 /***********************************************************************
267  *           DebugBreak   (KERNEL32.@)
268  *
269  *  Raises an exception so that a debugger (if attached)
270  *  can take some action.
271  */
272 void WINAPI DebugBreak(void)
273 {
274     DbgBreakPoint();
275 }
276
277 /***********************************************************************
278  *           DebugBreakProcess   (KERNEL32.@)
279  *
280  *  Raises an exception so that a debugger (if attached)
281  *  can take some action. Same as DebugBreak, but applies to any process.
282  */
283 BOOL WINAPI DebugBreakProcess(HANDLE hProc)
284 {
285     BOOL ret, self;
286
287     TRACE("(%08x)\n", hProc);
288
289     SERVER_START_REQ( debug_break )
290     {
291         req->handle = hProc;
292         ret = !wine_server_call_err( req );
293         self = ret && reply->self;
294     }
295     SERVER_END_REQ;
296     if (self) DbgBreakPoint();
297     return ret;
298 }
299
300
301 /***********************************************************************
302  *           DebugBreak   (KERNEL.203)
303  *
304  *  Raises an expection in a 16 bit application so that a debugger (if attached)
305  *  can take some action.
306  *
307  * BUGS
308  *
309  *  Only 386 compatible processors implemented.
310  */
311 void WINAPI DebugBreak16(
312     CONTEXT86 *context) /* [in/out] A pointer to the 386 compatible processor state. */
313 {
314 #ifdef __i386__
315     EXCEPTION_RECORD rec;
316
317     rec.ExceptionCode    = EXCEPTION_BREAKPOINT;
318     rec.ExceptionFlags   = 0;
319     rec.ExceptionRecord  = NULL;
320     rec.ExceptionAddress = (LPVOID)context->Eip;
321     rec.NumberParameters = 0;
322     NtRaiseException( &rec, context, TRUE );
323 #endif  /* defined(__i386__) */
324 }
325
326
327 /***********************************************************************
328  *           IsDebuggerPresent   (KERNEL32.@)
329  *
330  *  Allows a process to determine if there is a debugger attached.
331  *
332  * RETURNS
333  *
334  *  True if there is a debugger attached.
335  */
336 BOOL WINAPI IsDebuggerPresent(void)
337 {
338     BOOL ret = FALSE;
339     SERVER_START_REQ( get_process_info )
340     {
341         req->handle = GetCurrentProcess();
342         if (!wine_server_call_err( req )) ret = reply->debugged;
343     }
344     SERVER_END_REQ;
345     return ret;
346 }
347
348
349 /***********************************************************************
350  *           _DebugOutput                    (KERNEL.328)
351  */
352 void WINAPIV _DebugOutput( void )
353 {
354     VA_LIST16 valist;
355     WORD flags;
356     SEGPTR spec;
357     char caller[101];
358
359     /* Decode caller address */
360     if (!GetModuleName16( GetExePtr(CURRENT_STACK16->cs), caller, sizeof(caller) ))
361         sprintf( caller, "%04X:%04X", CURRENT_STACK16->cs, CURRENT_STACK16->ip );
362
363     /* Build debug message string */
364     VA_START16( valist );
365     flags = VA_ARG16( valist, WORD );
366     spec  = VA_ARG16( valist, SEGPTR );
367     /* FIXME: cannot use wvsnprintf16 from kernel */
368     /* wvsnprintf16( temp, sizeof(temp), MapSL(spec), valist ); */
369
370     /* Output */
371     FIXME("%s %04x %s\n", caller, flags, debugstr_a(MapSL(spec)) );
372 }
373
374 /***********************************************************************
375  *           DebugSetProcessKillOnExit                    (KERNEL32.@)
376  *
377  * Let a debugger decide wether a debuggee will be killed upon debugger
378  * termination
379  */
380 BOOL WINAPI DebugSetProcessKillOnExit(BOOL kill)
381 {
382     BOOL ret = FALSE;
383
384     SERVER_START_REQ( set_debugger_kill_on_exit )
385     {
386         req->kill_on_exit = kill;
387         ret = !wine_server_call_err( req );
388     }
389     SERVER_END_REQ;
390     return ret;
391 }
392