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