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