Implemented OpenThread on top of NtOpenThread.
[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 "ntstatus.h"
28 #include "kernel_private.h"
29 #include "kernel16_private.h"
30 #include "wine/debug.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(debugstr);
33
34
35 /******************************************************************************
36  *           WaitForDebugEvent   (KERNEL32.@)
37  *
38  *  Waits for a debugging event to occur in a process being debugged before
39  *  filling out the debug event structure.
40  *
41  * PARAMS
42  *  event   [O] Address of structure for event information.
43  *  timeout [I] Number of milliseconds to wait for event.
44  *
45  * RETURNS
46  *
47  *  Returns true if a debug event occurred and false if the call timed out.
48  */
49 BOOL WINAPI WaitForDebugEvent(
50     LPDEBUG_EVENT event,
51     DWORD         timeout)
52 {
53     BOOL ret;
54     DWORD res;
55
56     for (;;)
57     {
58         HANDLE wait = 0;
59         debug_event_t data;
60         SERVER_START_REQ( wait_debug_event )
61         {
62             req->get_handle = (timeout != 0);
63             wine_server_set_reply( req, &data, sizeof(data) );
64             if (!(ret = !wine_server_call_err( req ))) goto done;
65
66             if (!wine_server_reply_size(reply))  /* timeout */
67             {
68                 wait = reply->wait;
69                 ret = FALSE;
70                 goto done;
71             }
72             event->dwDebugEventCode = data.code;
73             event->dwProcessId      = (DWORD)reply->pid;
74             event->dwThreadId       = (DWORD)reply->tid;
75             switch(data.code)
76             {
77             case EXCEPTION_DEBUG_EVENT:
78                 event->u.Exception.ExceptionRecord = data.info.exception.record;
79                 event->u.Exception.dwFirstChance   = data.info.exception.first;
80                 break;
81             case CREATE_THREAD_DEBUG_EVENT:
82                 event->u.CreateThread.hThread           = data.info.create_thread.handle;
83                 event->u.CreateThread.lpThreadLocalBase = data.info.create_thread.teb;
84                 event->u.CreateThread.lpStartAddress    = data.info.create_thread.start;
85                 break;
86             case CREATE_PROCESS_DEBUG_EVENT:
87                 event->u.CreateProcessInfo.hFile                 = data.info.create_process.file;
88                 event->u.CreateProcessInfo.hProcess              = data.info.create_process.process;
89                 event->u.CreateProcessInfo.hThread               = data.info.create_process.thread;
90                 event->u.CreateProcessInfo.lpBaseOfImage         = data.info.create_process.base;
91                 event->u.CreateProcessInfo.dwDebugInfoFileOffset = data.info.create_process.dbg_offset;
92                 event->u.CreateProcessInfo.nDebugInfoSize        = data.info.create_process.dbg_size;
93                 event->u.CreateProcessInfo.lpThreadLocalBase     = data.info.create_process.teb;
94                 event->u.CreateProcessInfo.lpStartAddress        = data.info.create_process.start;
95                 event->u.CreateProcessInfo.lpImageName           = data.info.create_process.name;
96                 event->u.CreateProcessInfo.fUnicode              = data.info.create_process.unicode;
97                 break;
98             case EXIT_THREAD_DEBUG_EVENT:
99                 event->u.ExitThread.dwExitCode = data.info.exit.exit_code;
100                 break;
101             case EXIT_PROCESS_DEBUG_EVENT:
102                 event->u.ExitProcess.dwExitCode = data.info.exit.exit_code;
103                 break;
104             case LOAD_DLL_DEBUG_EVENT:
105                 event->u.LoadDll.hFile                 = data.info.load_dll.handle;
106                 event->u.LoadDll.lpBaseOfDll           = data.info.load_dll.base;
107                 event->u.LoadDll.dwDebugInfoFileOffset = data.info.load_dll.dbg_offset;
108                 event->u.LoadDll.nDebugInfoSize        = data.info.load_dll.dbg_size;
109                 event->u.LoadDll.lpImageName           = data.info.load_dll.name;
110                 event->u.LoadDll.fUnicode              = data.info.load_dll.unicode;
111                 break;
112             case UNLOAD_DLL_DEBUG_EVENT:
113                 event->u.UnloadDll.lpBaseOfDll = data.info.unload_dll.base;
114                 break;
115             case OUTPUT_DEBUG_STRING_EVENT:
116                 event->u.DebugString.lpDebugStringData  = data.info.output_string.string;
117                 event->u.DebugString.fUnicode           = data.info.output_string.unicode;
118                 event->u.DebugString.nDebugStringLength = data.info.output_string.length;
119                 break;
120             case RIP_EVENT:
121                 event->u.RipInfo.dwError = data.info.rip_info.error;
122                 event->u.RipInfo.dwType  = data.info.rip_info.type;
123                 break;
124             }
125         done:
126             /* nothing */ ;
127         }
128         SERVER_END_REQ;
129         if (ret) return TRUE;
130         if (!wait) break;
131         res = WaitForSingleObject( wait, timeout );
132         CloseHandle( wait );
133         if (res != STATUS_WAIT_0) break;
134     }
135     SetLastError( ERROR_SEM_TIMEOUT );
136     return FALSE;
137 }
138
139
140 /**********************************************************************
141  *           ContinueDebugEvent   (KERNEL32.@)
142  *
143  *  Enables a thread that previously produced a debug event to continue.
144  *
145  * PARAMS
146  *  pid    [I] The id of the process to continue.
147  *  tid    [I] The id of the thread to continue.
148  *  status [I] The rule to apply to unhandled exeptions.
149  *
150  * RETURNS
151  *
152  *  True if the debugger is listed as the processes owner and the process
153  *  and thread are valid.
154  */
155 BOOL WINAPI ContinueDebugEvent(
156     DWORD pid,
157     DWORD tid,
158     DWORD status)
159 {
160     BOOL ret;
161     SERVER_START_REQ( continue_debug_event )
162     {
163         req->pid    = pid;
164         req->tid    = tid;
165         req->status = status;
166         ret = !wine_server_call_err( req );
167     }
168     SERVER_END_REQ;
169     return ret;
170 }
171
172
173 /**********************************************************************
174  *           DebugActiveProcess   (KERNEL32.@)
175  *
176  *  Attempts to attach the debugger to a process.
177  *
178  * PARAMS
179  *  pid [I] The process to be debugged.
180  *
181  * RETURNS
182  *
183  *  True if the debugger was attached to process.
184  */
185 BOOL WINAPI DebugActiveProcess( DWORD pid )
186 {
187     BOOL ret;
188     SERVER_START_REQ( debug_process )
189     {
190         req->pid = pid;
191         req->attach = 1;
192         ret = !wine_server_call_err( req );
193     }
194     SERVER_END_REQ;
195     return ret;
196 }
197
198 /**********************************************************************
199  *           DebugActiveProcessStop   (KERNEL32.@)
200  *
201  *  Attempts to detach the debugger from a process.
202  *
203  * PARAMS
204  *  pid [I] The process to be detached.
205  *
206  * RETURNS
207  *
208  *  True if the debugger was detached from the process.
209  */
210 BOOL WINAPI DebugActiveProcessStop( DWORD pid )
211 {
212     BOOL ret;
213     SERVER_START_REQ( debug_process )
214     {
215         req->pid = pid;
216         req->attach = 0;
217         ret = !wine_server_call_err( req );
218     }
219     SERVER_END_REQ;
220     return ret;
221 }
222
223
224 /***********************************************************************
225  *           OutputDebugStringA   (KERNEL32.@)
226  *
227  *  Output by an application of an ascii string to a debugger (if attached)
228  *  and program log.
229  *
230  * PARAMS
231  *  str [I] The message to be logged and given to the debugger.
232  *
233  * RETURNS
234  *
235  *  Nothing.
236  */
237 void WINAPI OutputDebugStringA( LPCSTR str )
238 {
239     SERVER_START_REQ( output_debug_string )
240     {
241         req->string  = (void *)str;
242         req->unicode = 0;
243         req->length  = strlen(str) + 1;
244         wine_server_call( req );
245     }
246     SERVER_END_REQ;
247     WARN("%s\n", str);
248 }
249
250
251 /***********************************************************************
252  *           OutputDebugStringW   (KERNEL32.@)
253  *
254  *  Output by an application of a unicode string to a debugger (if attached)
255  *  and program log.
256  *
257  * PARAMS
258  *  str [I] The message to be logged and given to the debugger.
259  *
260  * RETURNS
261  *
262  *  Nothing.
263  */
264 void WINAPI OutputDebugStringW( LPCWSTR str )
265 {
266     SERVER_START_REQ( output_debug_string )
267     {
268         req->string  = (void *)str;
269         req->unicode = 1;
270         req->length  = (lstrlenW(str) + 1) * sizeof(WCHAR);
271         wine_server_call( req );
272     }
273     SERVER_END_REQ;
274     WARN("%s\n", debugstr_w(str));
275 }
276
277
278 /***********************************************************************
279  *           OutputDebugString   (KERNEL.115)
280  *
281  *  Output by a 16 bit application of an ascii string to a debugger (if attached)
282  *  and program log.
283  *
284  * PARAMS
285  *  str [I] The message to be logged and given to the debugger.
286  *
287  * RETURNS
288  */
289 void WINAPI OutputDebugString16( LPCSTR str )
290 {
291     OutputDebugStringA( str );
292 }
293
294
295 /***********************************************************************
296  *           DebugBreak   (KERNEL32.@)
297  *
298  *  Raises an exception so that a debugger (if attached)
299  *  can take some action.
300  *
301  * PARAMS
302  *
303  * RETURNS
304  */
305 void WINAPI DebugBreak(void)
306 {
307     DbgBreakPoint();
308 }
309
310 /***********************************************************************
311  *           DebugBreakProcess   (KERNEL32.@)
312  *
313  *  Raises an exception so that a debugger (if attached)
314  *  can take some action. Same as DebugBreak, but applies to any process.
315  *
316  * PARAMS
317  *  hProc [I] Process to break into.
318  *
319  * RETURNS
320  *
321  *  True if successful.
322  */
323 BOOL WINAPI DebugBreakProcess(HANDLE hProc)
324 {
325     BOOL ret, self;
326
327     TRACE("(%p)\n", hProc);
328
329     SERVER_START_REQ( debug_break )
330     {
331         req->handle = hProc;
332         ret = !wine_server_call_err( req );
333         self = ret && reply->self;
334     }
335     SERVER_END_REQ;
336     if (self) DbgBreakPoint();
337     return ret;
338 }
339
340
341 /***********************************************************************
342  *           DebugBreak   (KERNEL.203)
343  *
344  *  Raises an expection in a 16 bit application so that a debugger (if attached)
345  *  can take some action.
346  *
347  * PARAMS
348  *
349  * RETURNS
350  *
351  * BUGS
352  *
353  *  Only 386 compatible processors implemented.
354  */
355 void WINAPI DebugBreak16(
356     CONTEXT86 *context) /* [in/out] A pointer to the 386 compatible processor state. */
357 {
358 #ifdef __i386__
359     EXCEPTION_RECORD rec;
360
361     rec.ExceptionCode    = EXCEPTION_BREAKPOINT;
362     rec.ExceptionFlags   = 0;
363     rec.ExceptionRecord  = NULL;
364     rec.ExceptionAddress = (LPVOID)context->Eip;
365     rec.NumberParameters = 0;
366     NtRaiseException( &rec, context, TRUE );
367 #endif  /* defined(__i386__) */
368 }
369
370
371 /***********************************************************************
372  *           IsDebuggerPresent   (KERNEL32.@)
373  *
374  *  Allows a process to determine if there is a debugger attached.
375  *
376  * PARAMS
377  *
378  * RETURNS
379  *
380  *  True if there is a debugger attached.
381  */
382 BOOL WINAPI IsDebuggerPresent(void)
383 {
384     return NtCurrentTeb()->Peb->BeingDebugged;
385 }
386
387
388 /***********************************************************************
389  *           _DebugOutput                    (KERNEL.328)
390  */
391 void WINAPIV _DebugOutput( WORD flags, LPCSTR spec, VA_LIST16 valist )
392 {
393     char caller[101];
394
395     /* Decode caller address */
396     if (!GetModuleName16( GetExePtr(CURRENT_STACK16->cs), caller, sizeof(caller) ))
397         sprintf( caller, "%04X:%04X", CURRENT_STACK16->cs, CURRENT_STACK16->ip );
398
399     /* FIXME: cannot use wvsnprintf16 from kernel */
400     /* wvsnprintf16( temp, sizeof(temp), spec, valist ); */
401
402     /* Output */
403     FIXME("%s %04x %s\n", caller, flags, debugstr_a(spec) );
404 }
405
406 /***********************************************************************
407  *           DebugSetProcessKillOnExit                    (KERNEL32.@)
408  *
409  * Let a debugger decide whether a debuggee will be killed upon debugger
410  * termination.
411  *
412  * PARAMS
413  *  kill [I] If set to true then kill the process on exit.
414  *
415  * RETURNS
416  *  True if successful, false otherwise.
417  */
418 BOOL WINAPI DebugSetProcessKillOnExit(BOOL kill)
419 {
420     BOOL ret = FALSE;
421
422     SERVER_START_REQ( set_debugger_kill_on_exit )
423     {
424         req->kill_on_exit = kill;
425         ret = !wine_server_call_err( req );
426     }
427     SERVER_END_REQ;
428     return ret;
429 }