Spelling/alignment fixes.
[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 #if 0  /* FIXME: not correct */
272     int res;
273     int pid;
274
275     TRACE("(%08lx)\n", (DWORD)hProc);
276
277     SERVER_START_REQ( get_process_info )
278     {
279         req->handle = hProc;
280         res = wine_server_call_err( req );
281         pid = (int)reply->pid;
282     }
283     SERVER_END_REQ;
284     return !res && kill(pid, SIGINT) == 0;
285 #endif
286     return FALSE;
287 }
288
289
290 /***********************************************************************
291  *           DebugBreak   (KERNEL.203)
292  *
293  *  Raises an expection in a 16 bit application so that a debugger (if attached)
294  *  can take some action.
295  *
296  * BUGS
297  *
298  *  Only 386 compatible processors implemented.
299  */
300 void WINAPI DebugBreak16(
301     CONTEXT86 *context) /* [in/out] A pointer to the 386 compatible processor state. */
302 {
303 #ifdef __i386__
304     EXCEPTION_RECORD rec;
305
306     rec.ExceptionCode    = EXCEPTION_BREAKPOINT;
307     rec.ExceptionFlags   = 0;
308     rec.ExceptionRecord  = NULL;
309     rec.ExceptionAddress = (LPVOID)context->Eip;
310     rec.NumberParameters = 0;
311     NtRaiseException( &rec, context, TRUE );
312 #endif  /* defined(__i386__) */
313 }
314
315
316 /***********************************************************************
317  *           IsDebuggerPresent   (KERNEL32.@)
318  *
319  *  Allows a process to determine if there is a debugger attached.
320  *
321  * RETURNS
322  *
323  *  True if there is a debugger attached.
324  */
325 BOOL WINAPI IsDebuggerPresent(void)
326 {
327     BOOL ret = FALSE;
328     SERVER_START_REQ( get_process_info )
329     {
330         req->handle = GetCurrentProcess();
331         if (!wine_server_call_err( req )) ret = reply->debugged;
332     }
333     SERVER_END_REQ;
334     return ret;
335 }
336
337
338 /***********************************************************************
339  *           _DebugOutput                    (KERNEL.328)
340  */
341 void WINAPIV _DebugOutput( void )
342 {
343     VA_LIST16 valist;
344     WORD flags;
345     SEGPTR spec;
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     /* Build debug message string */
353     VA_START16( valist );
354     flags = VA_ARG16( valist, WORD );
355     spec  = VA_ARG16( valist, SEGPTR );
356     /* FIXME: cannot use wvsnprintf16 from kernel */
357     /* wvsnprintf16( temp, sizeof(temp), MapSL(spec), valist ); */
358
359     /* Output */
360     FIXME("%s %04x %s\n", caller, flags, debugstr_a(MapSL(spec)) );
361 }
362
363 /***********************************************************************
364  *           DebugSetProcessKillOnExit                    (KERNEL.328)
365  *
366  * Let a debugger decide wether a debuggee will be killed upon debugger
367  * termination
368  */
369 BOOL WINAPI DebugSetProcessKillOnExit(BOOL kill)
370 {
371     BOOL ret = FALSE;
372
373     SERVER_START_REQ( set_debugger_kill_on_exit )
374     {
375         req->kill_on_exit = kill;
376         ret = !wine_server_call_err( req );
377     }
378     SERVER_END_REQ;
379     return ret;
380 }
381