Stubs for CreateTimerQueue and DeleteTimerQueueEx.
[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                 break;
92             case EXIT_THREAD_DEBUG_EVENT:
93                 event->u.ExitThread.dwExitCode = data.info.exit.exit_code;
94                 break;
95             case EXIT_PROCESS_DEBUG_EVENT:
96                 event->u.ExitProcess.dwExitCode = data.info.exit.exit_code;
97                 break;
98             case LOAD_DLL_DEBUG_EVENT:
99                 event->u.LoadDll.hFile                 = data.info.load_dll.handle;
100                 event->u.LoadDll.lpBaseOfDll           = data.info.load_dll.base;
101                 event->u.LoadDll.dwDebugInfoFileOffset = data.info.load_dll.dbg_offset;
102                 event->u.LoadDll.nDebugInfoSize        = data.info.load_dll.dbg_size;
103                 event->u.LoadDll.lpImageName           = data.info.load_dll.name;
104                 event->u.LoadDll.fUnicode              = data.info.load_dll.unicode;
105                 break;
106             case UNLOAD_DLL_DEBUG_EVENT:
107                 event->u.UnloadDll.lpBaseOfDll = data.info.unload_dll.base;
108                 break;
109             case OUTPUT_DEBUG_STRING_EVENT:
110                 event->u.DebugString.lpDebugStringData  = data.info.output_string.string;
111                 event->u.DebugString.fUnicode           = data.info.output_string.unicode;
112                 event->u.DebugString.nDebugStringLength = data.info.output_string.length;
113                 break;
114             case RIP_EVENT:
115                 event->u.RipInfo.dwError = data.info.rip_info.error;
116                 event->u.RipInfo.dwType  = data.info.rip_info.type;
117                 break;
118             }
119         done:
120             /* nothing */ ;
121         }
122         SERVER_END_REQ;
123         if (ret) return TRUE;
124         if (!wait) break;
125         res = WaitForSingleObject( wait, timeout );
126         CloseHandle( wait );
127         if (res != STATUS_WAIT_0) break;
128     }
129     SetLastError( ERROR_SEM_TIMEOUT );
130     return FALSE;
131 }
132
133
134 /**********************************************************************
135  *           ContinueDebugEvent   (KERNEL32.@)
136  *
137  *  Enables a thread that previously produced a debug event to continue.
138  *
139  * RETURNS
140  *
141  *  True if the debugger is listed as the processes owner and the process
142  *  and thread are valid.
143  */
144 BOOL WINAPI ContinueDebugEvent(
145     DWORD pid,    /* [in] The id of the process to continue. */
146     DWORD tid,    /* [in] The id of the thread to continue. */
147     DWORD status) /* [in] The rule to apply to unhandled exeptions. */
148 {
149     BOOL ret;
150     SERVER_START_REQ( continue_debug_event )
151     {
152         req->pid    = pid;
153         req->tid    = tid;
154         req->status = status;
155         ret = !wine_server_call_err( req );
156     }
157     SERVER_END_REQ;
158     return ret;
159 }
160
161
162 /**********************************************************************
163  *           DebugActiveProcess   (KERNEL32.@)
164  *
165  *  Attempts to attach the debugger to a process.
166  *
167  * RETURNS
168  *
169  *  True if the debugger was attached to process.
170  */
171 BOOL WINAPI DebugActiveProcess(
172     DWORD pid) /* [in] The process to be debugged. */
173 {
174     BOOL ret;
175     SERVER_START_REQ( debug_process )
176     {
177         req->pid = pid;
178         req->attach = 1;
179         ret = !wine_server_call_err( req );
180     }
181     SERVER_END_REQ;
182     return ret;
183 }
184
185 /**********************************************************************
186  *           DebugActiveProcessStop   (KERNEL32.@)
187  *
188  *  Attempts to detach the debugger from a process.
189  *
190  * RETURNS
191  *
192  *  True if the debugger was detached from the process.
193  */
194 BOOL WINAPI DebugActiveProcessStop(
195     DWORD pid) /* [in] The process to be detached. */
196 {
197     BOOL ret;
198     SERVER_START_REQ( debug_process )
199     {
200         req->pid = pid;
201         req->attach = 0;
202         ret = !wine_server_call_err( req );
203     }
204     SERVER_END_REQ;
205     return ret;
206 }
207
208
209 /***********************************************************************
210  *           OutputDebugStringA   (KERNEL32.@)
211  *
212  *  Output by an application of a unicode string to a debugger (if attached)
213  *  and program log.
214  */
215 void WINAPI OutputDebugStringA(
216     LPCSTR str) /* [in] The message to be logged and given to the debugger. */
217 {
218     SERVER_START_REQ( output_debug_string )
219     {
220         req->string  = (void *)str;
221         req->unicode = 0;
222         req->length  = strlen(str) + 1;
223         wine_server_call( req );
224     }
225     SERVER_END_REQ;
226     WARN("%s\n", str);
227 }
228
229
230 /***********************************************************************
231  *           OutputDebugStringW   (KERNEL32.@)
232  *
233  *  Output by an appliccation of a unicode string to a debugger (if attached)
234  *  and program log.
235  */
236 void WINAPI OutputDebugStringW(
237     LPCWSTR str) /* [in] The message to be logged and given to the debugger. */
238 {
239     SERVER_START_REQ( output_debug_string )
240     {
241         req->string  = (void *)str;
242         req->unicode = 1;
243         req->length  = (lstrlenW(str) + 1) * sizeof(WCHAR);
244         wine_server_call( req );
245     }
246     SERVER_END_REQ;
247     WARN("%s\n", debugstr_w(str));
248 }
249
250
251 /***********************************************************************
252  *           OutputDebugString   (KERNEL.115)
253  *
254  *  Output by a 16 bit application of an ascii string to a debugger (if attached)
255  *  and program log.
256  */
257 void WINAPI OutputDebugString16(
258     LPCSTR str) /* [in] The message to be logged and given to the debugger. */
259 {
260     OutputDebugStringA( str );
261 }
262
263
264 /***********************************************************************
265  *           DebugBreak   (KERNEL32.@)
266  *
267  *  Raises an exception so that a debugger (if attached)
268  *  can take some action.
269  */
270 void WINAPI DebugBreak(void)
271 {
272     DbgBreakPoint();
273 }
274
275 /***********************************************************************
276  *           DebugBreakProcess   (KERNEL32.@)
277  *
278  *  Raises an exception so that a debugger (if attached)
279  *  can take some action. Same as DebugBreak, but applies to any process.
280  */
281 BOOL WINAPI DebugBreakProcess(HANDLE hProc)
282 {
283     BOOL ret, self;
284
285     TRACE("(%p)\n", hProc);
286
287     SERVER_START_REQ( debug_break )
288     {
289         req->handle = hProc;
290         ret = !wine_server_call_err( req );
291         self = ret && reply->self;
292     }
293     SERVER_END_REQ;
294     if (self) DbgBreakPoint();
295     return ret;
296 }
297
298
299 /***********************************************************************
300  *           DebugBreak   (KERNEL.203)
301  *
302  *  Raises an expection in a 16 bit application so that a debugger (if attached)
303  *  can take some action.
304  *
305  * BUGS
306  *
307  *  Only 386 compatible processors implemented.
308  */
309 void WINAPI DebugBreak16(
310     CONTEXT86 *context) /* [in/out] A pointer to the 386 compatible processor state. */
311 {
312 #ifdef __i386__
313     EXCEPTION_RECORD rec;
314
315     rec.ExceptionCode    = EXCEPTION_BREAKPOINT;
316     rec.ExceptionFlags   = 0;
317     rec.ExceptionRecord  = NULL;
318     rec.ExceptionAddress = (LPVOID)context->Eip;
319     rec.NumberParameters = 0;
320     NtRaiseException( &rec, context, TRUE );
321 #endif  /* defined(__i386__) */
322 }
323
324
325 /***********************************************************************
326  *           IsDebuggerPresent   (KERNEL32.@)
327  *
328  *  Allows a process to determine if there is a debugger attached.
329  *
330  * RETURNS
331  *
332  *  True if there is a debugger attached.
333  */
334 BOOL WINAPI IsDebuggerPresent(void)
335 {
336     BOOL ret = FALSE;
337     SERVER_START_REQ( get_process_info )
338     {
339         req->handle = GetCurrentProcess();
340         if (!wine_server_call_err( req )) ret = reply->debugged;
341     }
342     SERVER_END_REQ;
343     return ret;
344 }
345
346
347 /***********************************************************************
348  *           _DebugOutput                    (KERNEL.328)
349  */
350 void WINAPIV _DebugOutput( void )
351 {
352     VA_LIST16 valist;
353     WORD flags;
354     SEGPTR spec;
355     char caller[101];
356
357     /* Decode caller address */
358     if (!GetModuleName16( GetExePtr(CURRENT_STACK16->cs), caller, sizeof(caller) ))
359         sprintf( caller, "%04X:%04X", CURRENT_STACK16->cs, CURRENT_STACK16->ip );
360
361     /* Build debug message string */
362     VA_START16( valist );
363     flags = VA_ARG16( valist, WORD );
364     spec  = VA_ARG16( valist, SEGPTR );
365     /* FIXME: cannot use wvsnprintf16 from kernel */
366     /* wvsnprintf16( temp, sizeof(temp), MapSL(spec), valist ); */
367
368     /* Output */
369     FIXME("%s %04x %s\n", caller, flags, debugstr_a(MapSL(spec)) );
370 }
371
372 /***********************************************************************
373  *           DebugSetProcessKillOnExit                    (KERNEL32.@)
374  *
375  * Let a debugger decide wether a debuggee will be killed upon debugger
376  * termination
377  */
378 BOOL WINAPI DebugSetProcessKillOnExit(BOOL kill)
379 {
380     BOOL ret = FALSE;
381
382     SERVER_START_REQ( set_debugger_kill_on_exit )
383     {
384         req->kill_on_exit = kill;
385         ret = !wine_server_call_err( req );
386     }
387     SERVER_END_REQ;
388     return ret;
389 }