Support for nonstandard baud rate in SetCommState.
[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 dugger 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         ret = !wine_server_call_err( req );
167     }
168     SERVER_END_REQ;
169     return ret;
170 }
171
172
173 /***********************************************************************
174  *           OutputDebugStringA   (KERNEL32.@)
175  *
176  *  Output by an application of a unicode string to a debugger (if attached)
177  *  and program log.
178  */
179 void WINAPI OutputDebugStringA(
180     LPCSTR str) /* [in] The message to be logged and given to the debugger. */
181 {
182     SERVER_START_REQ( output_debug_string )
183     {
184         req->string  = (void *)str;
185         req->unicode = 0;
186         req->length  = strlen(str) + 1;
187         wine_server_call( req );
188     }
189     SERVER_END_REQ;
190     WARN("%s\n", str);
191 }
192
193
194 /***********************************************************************
195  *           OutputDebugStringW   (KERNEL32.@)
196  *
197  *  Output by an appliccation of a unicode string to a debugger (if attached)
198  *  and program log.
199  */
200 void WINAPI OutputDebugStringW(
201     LPCWSTR str) /* [in] The message to be logged and given to the debugger. */
202 {
203     SERVER_START_REQ( output_debug_string )
204     {
205         req->string  = (void *)str;
206         req->unicode = 1;
207         req->length  = (lstrlenW(str) + 1) * sizeof(WCHAR);
208         wine_server_call( req );
209     }
210     SERVER_END_REQ;
211     WARN("%s\n", debugstr_w(str));
212 }
213
214
215 /***********************************************************************
216  *           OutputDebugString   (KERNEL.115)
217  *
218  *  Output by a 16 bit application of an ascii string to a debugger (if attached)
219  *  and program log.
220  */
221 void WINAPI OutputDebugString16(
222     LPCSTR str) /* [in] The message to be logged and given to the debugger. */
223 {
224     OutputDebugStringA( str );
225 }
226
227
228 /***********************************************************************
229  *           DebugBreak   (KERNEL32.@)
230  *
231  *  Raises an exception so that a debugger (if attached)
232  *  can take some action.
233  */
234 void WINAPI DebugBreak(void)
235 {
236     DbgBreakPoint();
237 }
238
239
240 /***********************************************************************
241  *           DebugBreak   (KERNEL.203)
242  *
243  *  Raises an expection in a 16 bit application so that a debugger (if attached)
244  *  can take some action.
245  *
246  * BUGS
247  *
248  *  Only 386 compatible processors implemented.
249  */
250 void WINAPI DebugBreak16(
251     CONTEXT86 *context) /* [in/out] A pointer to the 386 compatible processor state. */
252 {
253 #ifdef __i386__
254     EXCEPTION_RECORD rec;
255
256     rec.ExceptionCode    = EXCEPTION_BREAKPOINT;
257     rec.ExceptionFlags   = 0;
258     rec.ExceptionRecord  = NULL;
259     rec.ExceptionAddress = (LPVOID)context->Eip;
260     rec.NumberParameters = 0;
261     NtRaiseException( &rec, context, TRUE );
262 #endif  /* defined(__i386__) */
263 }
264
265
266 /***********************************************************************
267  *           IsDebuggerPresent   (KERNEL32.@)
268  *
269  *  Allows a process to determine if there is a debugger attached.
270  *
271  * RETURNS
272  *
273  *  True if there is a debugger attached.
274  */
275 BOOL WINAPI IsDebuggerPresent(void)
276 {
277     BOOL ret = FALSE;
278     SERVER_START_REQ( get_process_info )
279     {
280         req->handle = GetCurrentProcess();
281         if (!wine_server_call_err( req )) ret = reply->debugged;
282     }
283     SERVER_END_REQ;
284     return ret;
285 }
286
287
288 /***********************************************************************
289  *           _DebugOutput                    (KERNEL.328)
290  */
291 void WINAPIV _DebugOutput( void )
292 {
293     VA_LIST16 valist;
294     WORD flags;
295     SEGPTR spec;
296     char caller[101];
297
298     /* Decode caller address */
299     if (!GetModuleName16( GetExePtr(CURRENT_STACK16->cs), caller, sizeof(caller) ))
300         sprintf( caller, "%04X:%04X", CURRENT_STACK16->cs, CURRENT_STACK16->ip );
301
302     /* Build debug message string */
303     VA_START16( valist );
304     flags = VA_ARG16( valist, WORD );
305     spec  = VA_ARG16( valist, SEGPTR );
306     /* FIXME: cannot use wvsnprintf16 from kernel */
307     /* wvsnprintf16( temp, sizeof(temp), MapSL(spec), valist ); */
308
309     /* Output */
310     FIXME("%s %04x %s\n", caller, flags, debugstr_a(MapSL(spec)) );
311 }