Fixed a few problems with DCX_* flags handling.
[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_VAR_REQ( wait_debug_event, sizeof(*data) )
41         {
42             req->get_handle = (timeout != 0);
43             if (!(ret = !SERVER_CALL_ERR())) goto done;
44
45             if (!server_data_size(req))  /* timeout */
46             {
47                 wait = req->wait;
48                 ret = FALSE;
49                 goto done;
50             }
51             data = server_data_ptr(req);
52             event->dwDebugEventCode = data->code;
53             event->dwProcessId      = (DWORD)req->pid;
54             event->dwThreadId       = (DWORD)req->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         }
109         SERVER_END_VAR_REQ;
110         if (ret) return TRUE;
111         if (!wait) break;
112         res = WaitForSingleObject( wait, timeout );
113         CloseHandle( wait );
114         if (res != STATUS_WAIT_0) break;
115     }
116     SetLastError( ERROR_SEM_TIMEOUT );
117     return FALSE;
118 }
119
120
121 /**********************************************************************
122  *           ContinueDebugEvent   (KERNEL32.@)
123  *
124  *  Enables a thread that previously produced a debug event to continue.
125  *
126  * RETURNS
127  *
128  *  True if the debugger is listed as the processes owner and the process
129  *  and thread are valid.
130  */
131 BOOL WINAPI ContinueDebugEvent(
132     DWORD pid,    /* [in] The id of the process to continue. */
133     DWORD tid,    /* [in] The id of the thread to continue. */
134     DWORD status) /* [in] The rule to apply to unhandled exeptions. */
135 {
136     BOOL ret;
137     SERVER_START_REQ( continue_debug_event )
138     {
139         req->pid    = (void *)pid;
140         req->tid    = (void *)tid;
141         req->status = status;
142         ret = !SERVER_CALL_ERR();
143     }
144     SERVER_END_REQ;
145     return ret;
146 }
147
148
149 /**********************************************************************
150  *           DebugActiveProcess   (KERNEL32.@)
151  *
152  *  Attempts to attach the dugger to a process.
153  *
154  * RETURNS
155  *
156  *  True if the debugger was attached to process.
157  */
158 BOOL WINAPI DebugActiveProcess(
159     DWORD pid) /* [in] The process to be debugged. */
160 {
161     BOOL ret;
162     SERVER_START_REQ( debug_process )
163     {
164         req->pid = (void *)pid;
165         ret = !SERVER_CALL_ERR();
166     }
167     SERVER_END_REQ;
168     return ret;
169 }
170
171
172 /***********************************************************************
173  *           OutputDebugStringA   (KERNEL32.@)
174  *
175  *  Output by an application of a unicode string to a debugger (if attached)
176  *  and program log.
177  */
178 void WINAPI OutputDebugStringA(
179     LPCSTR str) /* [in] The message to be logged and given to the debugger. */
180 {
181     SERVER_START_REQ( output_debug_string )
182     {
183         req->string  = (void *)str;
184         req->unicode = 0;
185         req->length  = strlen(str) + 1;
186         SERVER_CALL();
187     }
188     SERVER_END_REQ;
189     WARN("%s\n", str);
190 }
191
192
193 /***********************************************************************
194  *           OutputDebugStringW   (KERNEL32.@)
195  *
196  *  Output by an appliccation of a unicode string to a debugger (if attached)
197  *  and program log.
198  */
199 void WINAPI OutputDebugStringW(
200     LPCWSTR str) /* [in] The message to be logged and given to the debugger. */
201 {
202     SERVER_START_REQ( output_debug_string )
203     {
204         req->string  = (void *)str;
205         req->unicode = 1;
206         req->length  = (lstrlenW(str) + 1) * sizeof(WCHAR);
207         SERVER_CALL();
208     }
209     SERVER_END_REQ;
210     WARN("%s\n", debugstr_w(str));
211 }
212
213
214 /***********************************************************************
215  *           OutputDebugString   (KERNEL.115)
216  *
217  *  Output by a 16 bit application of an ascii string to a debugger (if attached)
218  *  and program log.
219  */
220 void WINAPI OutputDebugString16(
221     LPCSTR str) /* [in] The message to be logged and given to the debugger. */
222 {
223     OutputDebugStringA( str );
224 }
225
226
227 /***********************************************************************
228  *           DebugBreak   (KERNEL32.@)
229  *
230  *  Raises an exception so that a debugger (if attached)
231  *  can take some action.
232  */
233 void WINAPI DebugBreak(void)
234 {
235     DbgBreakPoint();
236 }
237
238
239 /***********************************************************************
240  *           DebugBreak   (KERNEL.203)
241  *
242  *  Raises an expection in a 16 bit application so that a debugger (if attached)
243  *  can take some action.
244  *
245  * BUGS
246  *
247  *  Only 386 compatible processors implemented.
248  */
249 void WINAPI DebugBreak16(
250     CONTEXT86 *context) /* [in/out] A pointer to the 386 compatible processor state. */
251 {
252 #ifdef __i386__
253     EXCEPTION_RECORD rec;
254
255     rec.ExceptionCode    = EXCEPTION_BREAKPOINT;
256     rec.ExceptionFlags   = 0;
257     rec.ExceptionRecord  = NULL;
258     rec.ExceptionAddress = (LPVOID)context->Eip;
259     rec.NumberParameters = 0;
260     NtRaiseException( &rec, context, TRUE );
261 #endif  /* defined(__i386__) */
262 }
263
264
265 /***********************************************************************
266  *           IsDebuggerPresent   (KERNEL32.@)
267  *
268  *  Allows a process to determine if there is a debugger attached.
269  *
270  * RETURNS
271  *
272  *  True if there is a debugger attached.
273  */
274 BOOL WINAPI IsDebuggerPresent(void)
275 {
276     BOOL ret = FALSE;
277     SERVER_START_REQ( get_process_info )
278     {
279         req->handle = GetCurrentProcess();
280         if (!SERVER_CALL_ERR()) ret = req->debugged;
281     }
282     SERVER_END_REQ;
283     return ret;
284 }
285
286
287 /***********************************************************************
288  *           _DebugOutput                    (KERNEL.328)
289  */
290 void WINAPIV _DebugOutput( void )
291 {
292     VA_LIST16 valist;
293     WORD flags;
294     SEGPTR spec;
295     char caller[101];
296
297     /* Decode caller address */
298     if (!GetModuleName16( GetExePtr(CURRENT_STACK16->cs), caller, sizeof(caller) ))
299         sprintf( caller, "%04X:%04X", CURRENT_STACK16->cs, CURRENT_STACK16->ip );
300
301     /* Build debug message string */
302     VA_START16( valist );
303     flags = VA_ARG16( valist, WORD );
304     spec  = VA_ARG16( valist, SEGPTR );
305     /* FIXME: cannot use wvsnprintf16 from kernel */
306     /* wvsnprintf16( temp, sizeof(temp), MapSL(spec), valist ); */
307
308     /* Output */
309     FIXME("%s %04x %s\n", caller, flags, debugstr_a(MapSL(spec)) );
310 }