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